summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 12:26:52 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 12:26:52 -0700
commit3498d13b8090c0b0ef911409fbc503a7c4cca6ef (patch)
tree254ca00276e863d9fba25707690c66b2a04c49e9
parentdef7cb8cd4e3258db88050eaaca5438bcc3dafca (diff)
parent0c57dfcc6c1d037243c2f8fbf62eab3633326ec0 (diff)
Merge tag 'tty-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull TTY changes from Greg Kroah-Hartman: "As we skipped the merge window for 3.6-rc1 for the tty tree, everything is now settled down and working properly, so we are ready for 3.7-rc1. Here's the patchset, it's big, but the large changes are removing a firmware file and adding a staging tty driver (it depended on the tty core changes, so it's going through this tree instead of the staging tree.) All of these patches have been in the linux-next tree for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>" Fix up more-or-less trivial conflicts in - drivers/char/pcmcia/synclink_cs.c: tty NULL dereference fix vs tty_port_cts_enabled() helper function - drivers/staging/{Kconfig,Makefile}: add-add conflict (dgrp driver added close to other staging drivers) - drivers/staging/ipack/devices/ipoctal.c: "split ipoctal_channel from iopctal" vs "TTY: use tty_port_register_device" * tag 'tty-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (235 commits) tty/serial: Add kgdb_nmi driver tty/serial/amba-pl011: Quiesce interrupts in poll_get_char tty/serial/amba-pl011: Implement poll_init callback tty/serial/core: Introduce poll_init callback kdb: Turn KGDB_KDB=n stubs into static inlines kdb: Implement disable_nmi command kernel/debug: Mask KGDB NMI upon entry serial: pl011: handle corruption at high clock speeds serial: sccnxp: Make 'default' choice in switch last serial: sccnxp: Remove mask termios caps for SW flow control serial: sccnxp: Report actual baudrate back to core serial: samsung: Add poll_get_char & poll_put_char Powerpc 8xx CPM_UART setting MAXIDL register proportionaly to baud rate Powerpc 8xx CPM_UART maxidl should not depend on fifo size Powerpc 8xx CPM_UART too many interrupts Powerpc 8xx CPM_UART desynchronisation serial: set correct baud_base for EXSYS EX-41092 Dual 16950 serial: omap: fix the reciever line error case 8250: blacklist Winbond CIR port 8250_pnp: do pnp probe before legacy probe ...
-rw-r--r--Documentation/ABI/testing/sysfs-tty9
-rw-r--r--Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt14
-rw-r--r--Documentation/devicetree/bindings/tty/serial/of-serial.txt2
-rw-r--r--Documentation/serial/00-INDEX2
-rw-r--r--Documentation/serial/computone.txt520
-rw-r--r--arch/alpha/kernel/srmcons.c1
-rw-r--r--arch/arm/mach-omap2/serial.c18
-rw-r--r--arch/arm/mach-ux500/board-mop500.c21
-rw-r--r--arch/arm/plat-omap/include/plat/omap-serial.h50
-rw-r--r--arch/ia64/hp/sim/simserial.c3
-rw-r--r--arch/m68k/emu/nfcon.c4
-rw-r--r--arch/mips/cavium-octeon/serial.c30
-rw-r--r--arch/mips/sni/a20r.c32
-rw-r--r--arch/parisc/kernel/pdc_cons.c1
-rw-r--r--arch/um/drivers/line.c3
-rw-r--r--arch/xtensa/platforms/iss/console.c1
-rw-r--r--drivers/bluetooth/hci_ath.c2
-rw-r--r--drivers/char/mwave/mwavedd.c16
-rw-r--r--drivers/char/pcmcia/synclink_cs.c131
-rw-r--r--drivers/char/ttyprintk.c33
-rw-r--r--drivers/isdn/capi/capi.c3
-rw-r--r--drivers/isdn/gigaset/interface.c7
-rw-r--r--drivers/isdn/i4l/isdn_tty.c41
-rw-r--r--drivers/misc/ibmasm/uart.c16
-rw-r--r--drivers/misc/pti.c128
-rw-r--r--drivers/mmc/card/sdio_uart.c24
-rw-r--r--drivers/net/ethernet/sgi/ioc3-eth.c22
-rw-r--r--drivers/net/irda/irtty-sir.c10
-rw-r--r--drivers/net/usb/hso.c19
-rw-r--r--drivers/parport/parport_gsc.c1
-rw-r--r--drivers/parport/parport_serial.c11
-rw-r--r--drivers/s390/char/con3215.c28
-rw-r--r--drivers/s390/char/sclp_tty.c1
-rw-r--r--drivers/s390/char/sclp_vt220.c1
-rw-r--r--drivers/s390/char/tty3270.c34
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/dgrp/Kconfig9
-rw-r--r--drivers/staging/dgrp/Makefile12
-rw-r--r--drivers/staging/dgrp/README2
-rw-r--r--drivers/staging/dgrp/TODO13
-rw-r--r--drivers/staging/dgrp/dgrp_common.c200
-rw-r--r--drivers/staging/dgrp/dgrp_common.h208
-rw-r--r--drivers/staging/dgrp/dgrp_dpa_ops.c556
-rw-r--r--drivers/staging/dgrp/dgrp_driver.c110
-rw-r--r--drivers/staging/dgrp/dgrp_mon_ops.c346
-rw-r--r--drivers/staging/dgrp/dgrp_net_ops.c3737
-rw-r--r--drivers/staging/dgrp/dgrp_ports_ops.c170
-rw-r--r--drivers/staging/dgrp/dgrp_specproc.c822
-rw-r--r--drivers/staging/dgrp/dgrp_sysfs.c555
-rw-r--r--drivers/staging/dgrp/dgrp_tty.c3331
-rw-r--r--drivers/staging/dgrp/digirp.h129
-rw-r--r--drivers/staging/dgrp/drp.h693
-rw-r--r--drivers/staging/ipack/devices/ipoctal.c14
-rw-r--r--drivers/staging/serqt_usb2/serqt_usb2.c18
-rw-r--r--drivers/staging/speakup/serialio.h3
-rw-r--r--drivers/tty/Kconfig9
-rw-r--r--drivers/tty/amiserial.c45
-rw-r--r--drivers/tty/bfin_jtag_comm.c1
-rw-r--r--drivers/tty/cyclades.c102
-rw-r--r--drivers/tty/ehv_bytechan.c9
-rw-r--r--drivers/tty/hvc/Kconfig2
-rw-r--r--drivers/tty/hvc/hvc_console.c33
-rw-r--r--drivers/tty/hvc/hvcs.c82
-rw-r--r--drivers/tty/hvc/hvsi.c2
-rw-r--r--drivers/tty/hvc/hvsi_lib.c2
-rw-r--r--drivers/tty/ipwireless/network.c7
-rw-r--r--drivers/tty/ipwireless/tty.c2
-rw-r--r--drivers/tty/isicom.c13
-rw-r--r--drivers/tty/moxa.c39
-rw-r--r--drivers/tty/mxser.c63
-rw-r--r--drivers/tty/n_gsm.c144
-rw-r--r--drivers/tty/n_r3964.c10
-rw-r--r--drivers/tty/n_tty.c29
-rw-r--r--drivers/tty/nozomi.c4
-rw-r--r--drivers/tty/pty.c234
-rw-r--r--drivers/tty/rocket.c22
-rw-r--r--drivers/tty/serial/68328serial.c23
-rw-r--r--drivers/tty/serial/8250/8250.c156
-rw-r--r--drivers/tty/serial/8250/8250.h43
-rw-r--r--drivers/tty/serial/8250/8250_acorn.c22
-rw-r--r--drivers/tty/serial/8250/8250_dw.c38
-rw-r--r--drivers/tty/serial/8250/8250_gsc.c26
-rw-r--r--drivers/tty/serial/8250/8250_hp300.c26
-rw-r--r--drivers/tty/serial/8250/8250_pci.c214
-rw-r--r--drivers/tty/serial/8250/8250_pnp.c59
-rw-r--r--drivers/tty/serial/8250/Kconfig16
-rw-r--r--drivers/tty/serial/8250/Makefile5
-rw-r--r--drivers/tty/serial/8250/serial_cs.c30
-rw-r--r--drivers/tty/serial/Kconfig73
-rw-r--r--drivers/tty/serial/Makefile5
-rw-r--r--drivers/tty/serial/altera_uart.c6
-rw-r--r--drivers/tty/serial/amba-pl010.c15
-rw-r--r--drivers/tty/serial/amba-pl011.c177
-rw-r--r--drivers/tty/serial/bfin_uart.c2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_core.c23
-rw-r--r--drivers/tty/serial/crisv10.c45
-rw-r--r--drivers/tty/serial/ifx6x60.c4
-rw-r--r--drivers/tty/serial/imx.c13
-rw-r--r--drivers/tty/serial/ioc3_serial.c3
-rw-r--r--drivers/tty/serial/ioc4_serial.c5
-rw-r--r--drivers/tty/serial/jsm/jsm_tty.c8
-rw-r--r--drivers/tty/serial/kgdb_nmi.c402
-rw-r--r--drivers/tty/serial/kgdboc.c9
-rw-r--r--drivers/tty/serial/lpc32xx_hs.c823
-rw-r--r--drivers/tty/serial/m32r_sio.c36
-rw-r--r--drivers/tty/serial/max3100.c26
-rw-r--r--drivers/tty/serial/max3107.c1215
-rw-r--r--drivers/tty/serial/max3107.h441
-rw-r--r--drivers/tty/serial/max310x.c1260
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c8
-rw-r--r--drivers/tty/serial/msm_serial.c2
-rw-r--r--drivers/tty/serial/msm_smd_tty.c8
-rw-r--r--drivers/tty/serial/mxs-auart.c8
-rw-r--r--drivers/tty/serial/of_serial.c13
-rw-r--r--drivers/tty/serial/omap-serial.c885
-rw-r--r--drivers/tty/serial/pch_uart.c4
-rw-r--r--drivers/tty/serial/pxa.c14
-rw-r--r--drivers/tty/serial/samsung.c95
-rw-r--r--drivers/tty/serial/sc26xx.c4
-rw-r--r--drivers/tty/serial/sccnxp.c990
-rw-r--r--drivers/tty/serial/serial_core.c251
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c8
-rw-r--r--drivers/tty/serial/sunsu.c8
-rw-r--r--drivers/tty/synclink.c86
-rw-r--r--drivers/tty/synclink_gt.c37
-rw-r--r--drivers/tty/synclinkmp.c58
-rw-r--r--drivers/tty/tty_io.c375
-rw-r--r--drivers/tty/tty_ioctl.c100
-rw-r--r--drivers/tty/tty_ldisc.c78
-rw-r--r--drivers/tty/tty_mutex.c71
-rw-r--r--drivers/tty/tty_port.c94
-rw-r--r--drivers/tty/vt/keyboard.c50
-rw-r--r--drivers/tty/vt/vt.c141
-rw-r--r--drivers/usb/class/cdc-acm.c5
-rw-r--r--drivers/usb/gadget/u_serial.c3
-rw-r--r--drivers/usb/serial/ark3116.c4
-rw-r--r--drivers/usb/serial/belkin_sa.c2
-rw-r--r--drivers/usb/serial/console.c4
-rw-r--r--drivers/usb/serial/cp210x.c8
-rw-r--r--drivers/usb/serial/cypress_m8.c40
-rw-r--r--drivers/usb/serial/digi_acceleport.c14
-rw-r--r--drivers/usb/serial/empeg.c2
-rw-r--r--drivers/usb/serial/f81232.c3
-rw-r--r--drivers/usb/serial/ftdi_sio.c2
-rw-r--r--drivers/usb/serial/io_edgeport.c12
-rw-r--r--drivers/usb/serial/io_ti.c12
-rw-r--r--drivers/usb/serial/ir-usb.c2
-rw-r--r--drivers/usb/serial/iuu_phoenix.c28
-rw-r--r--drivers/usb/serial/keyspan.c6
-rw-r--r--drivers/usb/serial/keyspan_pda.c4
-rw-r--r--drivers/usb/serial/kl5kusb105.c18
-rw-r--r--drivers/usb/serial/kobil_sct.c14
-rw-r--r--drivers/usb/serial/mct_u232.c4
-rw-r--r--drivers/usb/serial/metro-usb.c6
-rw-r--r--drivers/usb/serial/mos7720.c14
-rw-r--r--drivers/usb/serial/mos7840.c12
-rw-r--r--drivers/usb/serial/oti6858.c10
-rw-r--r--drivers/usb/serial/pl2303.c6
-rw-r--r--drivers/usb/serial/quatech2.c4
-rw-r--r--drivers/usb/serial/sierra.c2
-rw-r--r--drivers/usb/serial/spcp8x5.c12
-rw-r--r--drivers/usb/serial/ssu100.c4
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c10
-rw-r--r--drivers/usb/serial/usb-serial.c7
-rw-r--r--drivers/usb/serial/usb_wwan.c2
-rw-r--r--drivers/usb/serial/whiteheat.c2
-rw-r--r--firmware/Makefile1
-rw-r--r--firmware/intelliport2.bin.ihex2147
-rw-r--r--fs/compat_ioctl.c6
-rw-r--r--include/linux/Kbuild4
-rw-r--r--include/linux/amba/serial.h1
-rw-r--r--include/linux/cd1400.h292
-rw-r--r--include/linux/cdk.h486
-rw-r--r--include/linux/comstats.h119
-rw-r--r--include/linux/generic_serial.h35
-rw-r--r--include/linux/istallion.h123
-rw-r--r--include/linux/kbd_kern.h13
-rw-r--r--include/linux/kdb.h29
-rw-r--r--include/linux/kgdb.h13
-rw-r--r--include/linux/pci_ids.h1
-rw-r--r--include/linux/platform_data/max310x.h67
-rw-r--r--include/linux/platform_data/sccnxp.h93
-rw-r--r--include/linux/sc26198.h533
-rw-r--r--include/linux/serial.h81
-rw-r--r--include/linux/serial167.h157
-rw-r--r--include/linux/serial_8250.h33
-rw-r--r--include/linux/serial_core.h8
-rw-r--r--include/linux/serial_reg.h4
-rw-r--r--include/linux/stallion.h147
-rw-r--r--include/linux/tty.h92
-rw-r--r--include/linux/tty_driver.h47
-rw-r--r--include/linux/tty_flags.h78
-rw-r--r--include/net/irda/ircomm_tty.h17
-rw-r--r--kernel/debug/debug_core.c14
-rw-r--r--kernel/debug/kdb/kdb_main.c31
-rw-r--r--net/bluetooth/rfcomm/tty.c10
-rw-r--r--net/irda/ircomm/ircomm_param.c5
-rw-r--r--net/irda/ircomm/ircomm_tty.c320
-rw-r--r--net/irda/ircomm/ircomm_tty_attach.c40
-rw-r--r--net/irda/ircomm/ircomm_tty_ioctl.c33
201 files changed, 18056 insertions, 8963 deletions
diff --git a/Documentation/ABI/testing/sysfs-tty b/Documentation/ABI/testing/sysfs-tty
index b138b663bf54..0c430150d929 100644
--- a/Documentation/ABI/testing/sysfs-tty
+++ b/Documentation/ABI/testing/sysfs-tty
@@ -17,3 +17,12 @@ Description:
device, like 'tty1'.
The file supports poll() to detect virtual
console switches.
+
+What: /sys/class/tty/ttyS0/uartclk
+Date: Sep 2012
+Contact: Tomas Hlavacek <tmshlvck@gmail.com>
+Description:
+ Shows the current uartclk value associated with the
+ UART port in serial_core, that is bound to TTY like ttyS0.
+ uartclk = 16 * baud_base
+
diff --git a/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt b/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt
new file mode 100644
index 000000000000..0d439dfc1aa5
--- /dev/null
+++ b/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt
@@ -0,0 +1,14 @@
+* NXP LPC32xx SoC High Speed UART
+
+Required properties:
+- compatible: Should be "nxp,lpc3220-hsuart"
+- reg: Should contain registers location and length
+- interrupts: Should contain interrupt
+
+Example:
+
+ uart1: serial@40014000 {
+ compatible = "nxp,lpc3220-hsuart";
+ reg = <0x40014000 0x1000>;
+ interrupts = <26 0>;
+ };
diff --git a/Documentation/devicetree/bindings/tty/serial/of-serial.txt b/Documentation/devicetree/bindings/tty/serial/of-serial.txt
index 0847fdeee11a..ba385f2e0ddc 100644
--- a/Documentation/devicetree/bindings/tty/serial/of-serial.txt
+++ b/Documentation/devicetree/bindings/tty/serial/of-serial.txt
@@ -25,6 +25,8 @@ Optional properties:
accesses to the UART (e.g. TI davinci).
- used-by-rtas : set to indicate that the port is in use by the OpenFirmware
RTAS and should not be registered.
+- no-loopback-test: set to indicate that the port does not implements loopback
+ test mode
Example:
diff --git a/Documentation/serial/00-INDEX b/Documentation/serial/00-INDEX
index e09468ad3cb1..f7b0c7dc25ef 100644
--- a/Documentation/serial/00-INDEX
+++ b/Documentation/serial/00-INDEX
@@ -2,8 +2,6 @@
- this file.
README.cycladesZ
- info on Cyclades-Z firmware loading.
-computone.txt
- - info on Computone Intelliport II/Plus Multiport Serial Driver.
digiepca.txt
- info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
hayes-esp.txt
diff --git a/Documentation/serial/computone.txt b/Documentation/serial/computone.txt
deleted file mode 100644
index a6a1158ea2ba..000000000000
--- a/Documentation/serial/computone.txt
+++ /dev/null
@@ -1,520 +0,0 @@
-NOTE: This is an unmaintained driver. It is not guaranteed to work due to
-changes made in the tty layer in 2.6. If you wish to take over maintenance of
-this driver, contact Michael Warfield <mhw@wittsend.com>.
-
-Changelog:
-----------
-11-01-2001: Original Document
-
-10-29-2004: Minor misspelling & format fix, update status of driver.
- James Nelson <james4765@gmail.com>
-
-Computone Intelliport II/Plus Multiport Serial Driver
------------------------------------------------------
-
-Release Notes For Linux Kernel 2.2 and higher.
-These notes are for the drivers which have already been integrated into the
-kernel and have been tested on Linux kernels 2.0, 2.2, 2.3, and 2.4.
-
-Version: 1.2.14
-Date: 11/01/2001
-Historical Author: Andrew Manison <amanison@america.net>
-Primary Author: Doug McNash
-
-This file assumes that you are using the Computone drivers which are
-integrated into the kernel sources. For updating the drivers or installing
-drivers into kernels which do not already have Computone drivers, please
-refer to the instructions in the README.computone file in the driver patch.
-
-
-1. INTRODUCTION
-
-This driver supports the entire family of Intelliport II/Plus controllers
-with the exception of the MicroChannel controllers. It does not support
-products previous to the Intelliport II.
-
-This driver was developed on the v2.0.x Linux tree and has been tested up
-to v2.4.14; it will probably not work with earlier v1.X kernels,.
-
-
-2. QUICK INSTALLATION
-
-Hardware - If you have an ISA card, find a free interrupt and io port.
- List those in use with `cat /proc/interrupts` and
- `cat /proc/ioports`. Set the card dip switches to a free
- address. You may need to configure your BIOS to reserve an
- irq for an ISA card. PCI and EISA parameters are set
- automagically. Insert card into computer with the power off
- before or after drivers installation.
-
- Note the hardware address from the Computone ISA cards installed into
- the system. These are required for editing ip2.c or editing
- /etc/modprobe.d/*.conf, or for specification on the modprobe
- command line.
-
- Note that the /etc/modules.conf should be used for older (pre-2.6)
- kernels.
-
-Software -
-
-Module installation:
-
-a) Determine free irq/address to use if any (configure BIOS if need be)
-b) Run "make config" or "make menuconfig" or "make xconfig"
- Select (m) module for CONFIG_COMPUTONE under character
- devices. CONFIG_PCI and CONFIG_MODULES also may need to be set.
-c) Set address on ISA cards then:
- edit /usr/src/linux/drivers/char/ip2.c if needed
- or
- edit config file in /etc/modprobe.d/ if needed (module).
- or both to match this setting.
-d) Run "make modules"
-e) Run "make modules_install"
-f) Run "/sbin/depmod -a"
-g) install driver using `modprobe ip2 <options>` (options listed below)
-h) run ip2mkdev (either the script below or the binary version)
-
-
-Kernel installation:
-
-a) Determine free irq/address to use if any (configure BIOS if need be)
-b) Run "make config" or "make menuconfig" or "make xconfig"
- Select (y) kernel for CONFIG_COMPUTONE under character
- devices. CONFIG_PCI may need to be set if you have PCI bus.
-c) Set address on ISA cards then:
- edit /usr/src/linux/drivers/char/ip2.c
- (Optional - may be specified on kernel command line now)
-d) Run "make zImage" or whatever target you prefer.
-e) mv /usr/src/linux/arch/x86/boot/zImage to /boot.
-f) Add new config for this kernel into /etc/lilo.conf, run "lilo"
- or copy to a floppy disk and boot from that floppy disk.
-g) Reboot using this kernel
-h) run ip2mkdev (either the script below or the binary version)
-
-Kernel command line options:
-
-When compiling the driver into the kernel, io and irq may be
-compiled into the driver by editing ip2.c and setting the values for
-io and irq in the appropriate array. An alternative is to specify
-a command line parameter to the kernel at boot up.
-
- ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
-
-Note that this order is very different from the specifications for the
-modload parameters which have separate IRQ and IO specifiers.
-
-The io port also selects PCI (1) and EISA (2) boards.
-
- io=0 No board
- io=1 PCI board
- io=2 EISA board
- else ISA board io address
-
-You only need to specify the boards which are present.
-
- Examples:
-
- 2 PCI boards:
-
- ip2=1,0,1,0
-
- 1 ISA board at 0x310 irq 5:
-
- ip2=0x310,5
-
-This can be added to and "append" option in lilo.conf similar to this:
-
- append="ip2=1,0,1,0"
-
-
-3. INSTALLATION
-
-Previously, the driver sources were packaged with a set of patch files
-to update the character drivers' makefile and configuration file, and other
-kernel source files. A build script (ip2build) was included which applies
-the patches if needed, and build any utilities needed.
-What you receive may be a single patch file in conventional kernel
-patch format build script. That form can also be applied by
-running patch -p1 < ThePatchFile. Otherwise run ip2build.
-
-The driver can be installed as a module (recommended) or built into the
-kernel. This is selected as for other drivers through the `make config`
-command from the root of the Linux source tree. If the driver is built
-into the kernel you will need to edit the file ip2.c to match the boards
-you are installing. See that file for instructions. If the driver is
-installed as a module the configuration can also be specified on the
-modprobe command line as follows:
-
- modprobe ip2 irq=irq1,irq2,irq3,irq4 io=addr1,addr2,addr3,addr4
-
-where irqnum is one of the valid Intelliport II interrupts (3,4,5,7,10,11,
-12,15) and addr1-4 are the base addresses for up to four controllers. If
-the irqs are not specified the driver uses the default in ip2.c (which
-selects polled mode). If no base addresses are specified the defaults in
-ip2.c are used. If you are autoloading the driver module with kerneld or
-kmod the base addresses and interrupt number must also be set in ip2.c
-and recompile or just insert and options line in /etc/modprobe.d/*.conf or both.
-The options line is equivalent to the command line and takes precedence over
-what is in ip2.c.
-
-config sample to put /etc/modprobe.d/*.conf:
- options ip2 io=1,0x328 irq=1,10
- alias char-major-71 ip2
- alias char-major-72 ip2
- alias char-major-73 ip2
-
-The equivalent in ip2.c:
-
-static int io[IP2_MAX_BOARDS]= { 1, 0x328, 0, 0 };
-static int irq[IP2_MAX_BOARDS] = { 1, 10, -1, -1 };
-
-The equivalent for the kernel command line (in lilo.conf):
-
- append="ip2=1,1,0x328,10"
-
-
-Note: Both io and irq should be updated to reflect YOUR system. An "io"
- address of 1 or 2 indicates a PCI or EISA card in the board table.
- The PCI or EISA irq will be assigned automatically.
-
-Specifying an invalid or in-use irq will default the driver into
-running in polled mode for that card. If all irq entries are 0 then
-all cards will operate in polled mode.
-
-If you select the driver as part of the kernel run :
-
- make zlilo (or whatever you do to create a bootable kernel)
-
-If you selected a module run :
-
- make modules && make modules_install
-
-The utility ip2mkdev (see 5 and 7 below) creates all the device nodes
-required by the driver. For a device to be created it must be configured
-in the driver and the board must be installed. Only devices corresponding
-to real IntelliPort II ports are created. With multiple boards and expansion
-boxes this will leave gaps in the sequence of device names. ip2mkdev uses
-Linux tty naming conventions: ttyF0 - ttyF255 for normal devices, and
-cuf0 - cuf255 for callout devices.
-
-
-4. USING THE DRIVERS
-
-As noted above, the driver implements the ports in accordance with Linux
-conventions, and the devices should be interchangeable with the standard
-serial devices. (This is a key point for problem reporting: please make
-sure that what you are trying do works on the ttySx/cuax ports first; then
-tell us what went wrong with the ip2 ports!)
-
-Higher speeds can be obtained using the setserial utility which remaps
-38,400 bps (extb) to 57,600 bps, 115,200 bps, or a custom speed.
-Intelliport II installations using the PowerPort expansion module can
-use the custom speed setting to select the highest speeds: 153,600 bps,
-230,400 bps, 307,200 bps, 460,800bps and 921,600 bps. The base for
-custom baud rate configuration is fixed at 921,600 for cards/expansion
-modules with ST654's and 115200 for those with Cirrus CD1400's. This
-corresponds to the maximum bit rates those chips are capable.
-For example if the baud base is 921600 and the baud divisor is 18 then
-the custom rate is 921600/18 = 51200 bps. See the setserial man page for
-complete details. Of course if stty accepts the higher rates now you can
-use that as well as the standard ioctls().
-
-
-5. ip2mkdev and assorted utilities...
-
-Several utilities, including the source for a binary ip2mkdev utility are
-available under .../drivers/char/ip2. These can be build by changing to
-that directory and typing "make" after the kernel has be built. If you do
-not wish to compile the binary utilities, the shell script below can be
-cut out and run as "ip2mkdev" to create the necessary device files. To
-use the ip2mkdev script, you must have procfs enabled and the proc file
-system mounted on /proc.
-
-
-6. NOTES
-
-This is a release version of the driver, but it is impossible to test it
-in all configurations of Linux. If there is any anomalous behaviour that
-does not match the standard serial port's behaviour please let us know.
-
-
-7. ip2mkdev shell script
-
-Previously, this script was simply attached here. It is now attached as a
-shar archive to make it easier to extract the script from the documentation.
-To create the ip2mkdev shell script change to a convenient directory (/tmp
-works just fine) and run the following command:
-
- unshar Documentation/serial/computone.txt
- (This file)
-
-You should now have a file ip2mkdev in your current working directory with
-permissions set to execute. Running that script with then create the
-necessary devices for the Computone boards, interfaces, and ports which
-are present on you system at the time it is run.
-
-
-#!/bin/sh
-# This is a shell archive (produced by GNU sharutils 4.2.1).
-# To extract the files from this archive, save it to some FILE, remove
-# everything before the `!/bin/sh' line above, then type `sh FILE'.
-#
-# Made on 2001-10-29 10:32 EST by <mhw@alcove.wittsend.com>.
-# Source directory was `/home2/src/tmp'.
-#
-# Existing files will *not* be overwritten unless `-c' is specified.
-#
-# This shar contains:
-# length mode name
-# ------ ---------- ------------------------------------------
-# 4251 -rwxr-xr-x ip2mkdev
-#
-save_IFS="${IFS}"
-IFS="${IFS}:"
-gettext_dir=FAILED
-locale_dir=FAILED
-first_param="$1"
-for dir in $PATH
-do
- if test "$gettext_dir" = FAILED && test -f $dir/gettext \
- && ($dir/gettext --version >/dev/null 2>&1)
- then
- set `$dir/gettext --version 2>&1`
- if test "$3" = GNU
- then
- gettext_dir=$dir
- fi
- fi
- if test "$locale_dir" = FAILED && test -f $dir/shar \
- && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
- then
- locale_dir=`$dir/shar --print-text-domain-dir`
- fi
-done
-IFS="$save_IFS"
-if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
-then
- echo=echo
-else
- TEXTDOMAINDIR=$locale_dir
- export TEXTDOMAINDIR
- TEXTDOMAIN=sharutils
- export TEXTDOMAIN
- echo="$gettext_dir/gettext -s"
-fi
-if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 -a -f $$.touch; then
- shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
-elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 -a ! -f 123123592001.5 -a -f $$.touch; then
- shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
-elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 -a -f $$.touch; then
- shar_touch='touch -am $3$4$5$6$2 "$8"'
-else
- shar_touch=:
- echo
- $echo 'WARNING: not restoring timestamps. Consider getting and'
- $echo "installing GNU \`touch', distributed in GNU File Utilities..."
- echo
-fi
-rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch
-#
-if mkdir _sh17581; then
- $echo 'x -' 'creating lock directory'
-else
- $echo 'failed to create lock directory'
- exit 1
-fi
-# ============= ip2mkdev ==============
-if test -f 'ip2mkdev' && test "$first_param" != -c; then
- $echo 'x -' SKIPPING 'ip2mkdev' '(file already exists)'
-else
- $echo 'x -' extracting 'ip2mkdev' '(text)'
- sed 's/^X//' << 'SHAR_EOF' > 'ip2mkdev' &&
-#!/bin/sh -
-#
-# ip2mkdev
-#
-# Make or remove devices as needed for Computone Intelliport drivers
-#
-# First rule! If the dev file exists and you need it, don't mess
-# with it. That prevents us from screwing up open ttys, ownership
-# and permissions on a running system!
-#
-# This script will NOT remove devices that no longer exist if their
-# board or interface box has been removed. If you want to get rid
-# of them, you can manually do an "rm -f /dev/ttyF* /dev/cuaf*"
-# before running this script. Running this script will then recreate
-# all the valid devices.
-#
-# Michael H. Warfield
-# /\/\|=mhw=|\/\/
-# mhw@wittsend.com
-#
-# Updated 10/29/2000 for version 1.2.13 naming convention
-# under devfs. /\/\|=mhw=|\/\/
-#
-# Updated 03/09/2000 for devfs support in ip2 drivers. /\/\|=mhw=|\/\/
-#
-X
-if test -d /dev/ip2 ; then
-# This is devfs mode... We don't do anything except create symlinks
-# from the real devices to the old names!
-X cd /dev
-X echo "Creating symbolic links to devfs devices"
-X for i in `ls ip2` ; do
-X if test ! -L ip2$i ; then
-X # Remove it incase it wasn't a symlink (old device)
-X rm -f ip2$i
-X ln -s ip2/$i ip2$i
-X fi
-X done
-X for i in `( cd tts ; ls F* )` ; do
-X if test ! -L tty$i ; then
-X # Remove it incase it wasn't a symlink (old device)
-X rm -f tty$i
-X ln -s tts/$i tty$i
-X fi
-X done
-X for i in `( cd cua ; ls F* )` ; do
-X DEVNUMBER=`expr $i : 'F\(.*\)'`
-X if test ! -L cuf$DEVNUMBER ; then
-X # Remove it incase it wasn't a symlink (old device)
-X rm -f cuf$DEVNUMBER
-X ln -s cua/$i cuf$DEVNUMBER
-X fi
-X done
-X exit 0
-fi
-X
-if test ! -f /proc/tty/drivers
-then
-X echo "\
-Unable to check driver status.
-Make sure proc file system is mounted."
-X
-X exit 255
-fi
-X
-if test ! -f /proc/tty/driver/ip2
-then
-X echo "\
-Unable to locate ip2 proc file.
-Attempting to load driver"
-X
-X if /sbin/insmod ip2
-X then
-X if test ! -f /proc/tty/driver/ip2
-X then
-X echo "\
-Unable to locate ip2 proc file after loading driver.
-Driver initialization failure or driver version error.
-"
-X exit 255
-X fi
-X else
-X echo "Unable to load ip2 driver."
-X exit 255
-X fi
-fi
-X
-# Ok... So we got the driver loaded and we can locate the procfs files.
-# Next we need our major numbers.
-X
-TTYMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/tt/!d' -e 's/.*tt[^ ]*[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers`
-CUAMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/cu/!d' -e 's/.*cu[^ ]*[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers`
-BRDMAJOR=`sed -e '/^Driver: /!d' -e 's/.*IMajor=\([0-9]*\)[ ]*.*/\1/' < /proc/tty/driver/ip2`
-X
-echo "\
-TTYMAJOR = $TTYMAJOR
-CUAMAJOR = $CUAMAJOR
-BRDMAJOR = $BRDMAJOR
-"
-X
-# Ok... Now we should know our major numbers, if appropriate...
-# Now we need our boards and start the device loops.
-X
-grep '^Board [0-9]:' /proc/tty/driver/ip2 | while read token number type alltherest
-do
-X # The test for blank "type" will catch the stats lead-in lines
-X # if they exist in the file
-X if test "$type" = "vacant" -o "$type" = "Vacant" -o "$type" = ""
-X then
-X continue
-X fi
-X
-X BOARDNO=`expr "$number" : '\([0-9]\):'`
-X PORTS=`expr "$alltherest" : '.*ports=\([0-9]*\)' | tr ',' ' '`
-X MINORS=`expr "$alltherest" : '.*minors=\([0-9,]*\)' | tr ',' ' '`
-X
-X if test "$BOARDNO" = "" -o "$PORTS" = ""
-X then
-# This may be a bug. We should at least get this much information
-X echo "Unable to process board line"
-X continue
-X fi
-X
-X if test "$MINORS" = ""
-X then
-# Silently skip this one. This board seems to have no boxes
-X continue
-X fi
-X
-X echo "board $BOARDNO: $type ports = $PORTS; port numbers = $MINORS"
-X
-X if test "$BRDMAJOR" != ""
-X then
-X BRDMINOR=`expr $BOARDNO \* 4`
-X STSMINOR=`expr $BRDMINOR + 1`
-X if test ! -c /dev/ip2ipl$BOARDNO ; then
-X mknod /dev/ip2ipl$BOARDNO c $BRDMAJOR $BRDMINOR
-X fi
-X if test ! -c /dev/ip2stat$BOARDNO ; then
-X mknod /dev/ip2stat$BOARDNO c $BRDMAJOR $STSMINOR
-X fi
-X fi
-X
-X if test "$TTYMAJOR" != ""
-X then
-X PORTNO=$BOARDBASE
-X
-X for PORTNO in $MINORS
-X do
-X if test ! -c /dev/ttyF$PORTNO ; then
-X # We got the hardware but no device - make it
-X mknod /dev/ttyF$PORTNO c $TTYMAJOR $PORTNO
-X fi
-X done
-X fi
-X
-X if test "$CUAMAJOR" != ""
-X then
-X PORTNO=$BOARDBASE
-X
-X for PORTNO in $MINORS
-X do
-X if test ! -c /dev/cuf$PORTNO ; then
-X # We got the hardware but no device - make it
-X mknod /dev/cuf$PORTNO c $CUAMAJOR $PORTNO
-X fi
-X done
-X fi
-done
-X
-Xexit 0
-SHAR_EOF
- (set 20 01 10 29 10 32 01 'ip2mkdev'; eval "$shar_touch") &&
- chmod 0755 'ip2mkdev' ||
- $echo 'restore of' 'ip2mkdev' 'failed'
- if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
- && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
- md5sum -c << SHAR_EOF >/dev/null 2>&1 \
- || $echo 'ip2mkdev:' 'MD5 check failed'
-cb5717134509f38bad9fde6b1f79b4a4 ip2mkdev
-SHAR_EOF
- else
- shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'ip2mkdev'`"
- test 4251 -eq "$shar_count" ||
- $echo 'ip2mkdev:' 'original size' '4251,' 'current size' "$shar_count!"
- fi
-fi
-rm -fr _sh17581
-exit 0
diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c
index 3ea809430eda..5d5865204a1d 100644
--- a/arch/alpha/kernel/srmcons.c
+++ b/arch/alpha/kernel/srmcons.c
@@ -223,6 +223,7 @@ srmcons_init(void)
driver->subtype = SYSTEM_TYPE_SYSCONS;
driver->init_termios = tty_std_termios;
tty_set_operations(driver, &srmcons_ops);
+ tty_port_link_device(&srmcons_singleton.port, driver, 0);
err = tty_register_driver(driver);
if (err) {
put_tty_driver(driver);
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index c1b93c752d70..9e80d209d138 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -81,8 +81,9 @@ static struct omap_uart_port_info omap_serial_default_info[] __initdata = {
};
#ifdef CONFIG_PM
-static void omap_uart_enable_wakeup(struct platform_device *pdev, bool enable)
+static void omap_uart_enable_wakeup(struct device *dev, bool enable)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct omap_device *od = to_omap_device(pdev);
if (!od)
@@ -99,15 +100,17 @@ static void omap_uart_enable_wakeup(struct platform_device *pdev, bool enable)
* in Smartidle Mode When Configured for DMA Operations.
* WA: configure uart in force idle mode.
*/
-static void omap_uart_set_noidle(struct platform_device *pdev)
+static void omap_uart_set_noidle(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct omap_device *od = to_omap_device(pdev);
omap_hwmod_set_slave_idlemode(od->hwmods[0], HWMOD_IDLEMODE_NO);
}
-static void omap_uart_set_smartidle(struct platform_device *pdev)
+static void omap_uart_set_smartidle(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct omap_device *od = to_omap_device(pdev);
u8 idlemode;
@@ -120,10 +123,10 @@ static void omap_uart_set_smartidle(struct platform_device *pdev)
}
#else
-static void omap_uart_enable_wakeup(struct platform_device *pdev, bool enable)
+static void omap_uart_enable_wakeup(struct device *dev, bool enable)
{}
-static void omap_uart_set_noidle(struct platform_device *pdev) {}
-static void omap_uart_set_smartidle(struct platform_device *pdev) {}
+static void omap_uart_set_noidle(struct device *dev) {}
+static void omap_uart_set_smartidle(struct device *dev) {}
#endif /* CONFIG_PM */
#ifdef CONFIG_OMAP_MUX
@@ -304,6 +307,9 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
omap_up.dma_rx_timeout = info->dma_rx_timeout;
omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate;
omap_up.autosuspend_timeout = info->autosuspend_timeout;
+ omap_up.DTR_gpio = info->DTR_gpio;
+ omap_up.DTR_inverted = info->DTR_inverted;
+ omap_up.DTR_present = info->DTR_present;
pdata = &omap_up;
pdata_size = sizeof(struct omap_uart_port_info);
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index a534d8880de1..1d2e3c6f8b59 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -524,33 +524,12 @@ static struct stedma40_chan_cfg uart2_dma_cfg_tx = {
};
#endif
-#define PRCC_K_SOFTRST_SET 0x18
-#define PRCC_K_SOFTRST_CLEAR 0x1C
-static void ux500_uart0_reset(void)
-{
- void __iomem *prcc_rst_set, *prcc_rst_clr;
-
- prcc_rst_set = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE +
- PRCC_K_SOFTRST_SET);
- prcc_rst_clr = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE +
- PRCC_K_SOFTRST_CLEAR);
-
- /* Activate soft reset PRCC_K_SOFTRST_CLEAR */
- writel((readl(prcc_rst_clr) | 0x1), prcc_rst_clr);
- udelay(1);
-
- /* Release soft reset PRCC_K_SOFTRST_SET */
- writel((readl(prcc_rst_set) | 0x1), prcc_rst_set);
- udelay(1);
-}
-
static struct amba_pl011_data uart0_plat = {
#ifdef CONFIG_STE_DMA40
.dma_filter = stedma40_filter,
.dma_rx_param = &uart0_dma_cfg_rx,
.dma_tx_param = &uart0_dma_cfg_tx,
#endif
- .reset = ux500_uart0_reset,
};
static struct amba_pl011_data uart1_plat = {
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index 1a52725ffcf2..a531149823bb 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -18,7 +18,7 @@
#define __OMAP_SERIAL_H__
#include <linux/serial_core.h>
-#include <linux/platform_device.h>
+#include <linux/device.h>
#include <linux/pm_qos.h>
#include <plat/mux.h>
@@ -42,10 +42,10 @@
#define OMAP_UART_WER_MOD_WKUP 0X7F
/* Enable XON/XOFF flow control on output */
-#define OMAP_UART_SW_TX 0x04
+#define OMAP_UART_SW_TX 0x8
/* Enable XON/XOFF flow control on input */
-#define OMAP_UART_SW_RX 0x04
+#define OMAP_UART_SW_RX 0x2
#define OMAP_UART_SYSC_RESET 0X07
#define OMAP_UART_TCR_TRIG 0X0F
@@ -69,11 +69,14 @@ struct omap_uart_port_info {
unsigned int dma_rx_timeout;
unsigned int autosuspend_timeout;
unsigned int dma_rx_poll_rate;
+ int DTR_gpio;
+ int DTR_inverted;
+ int DTR_present;
int (*get_context_loss_count)(struct device *);
- void (*set_forceidle)(struct platform_device *);
- void (*set_noidle)(struct platform_device *);
- void (*enable_wakeup)(struct platform_device *, bool);
+ void (*set_forceidle)(struct device *);
+ void (*set_noidle)(struct device *);
+ void (*enable_wakeup)(struct device *, bool);
};
struct uart_omap_dma {
@@ -102,39 +105,4 @@ struct uart_omap_dma {
unsigned int rx_timeout;
};
-struct uart_omap_port {
- struct uart_port port;
- struct uart_omap_dma uart_dma;
- struct platform_device *pdev;
-
- unsigned char ier;
- unsigned char lcr;
- unsigned char mcr;
- unsigned char fcr;
- unsigned char efr;
- unsigned char dll;
- unsigned char dlh;
- unsigned char mdr1;
- unsigned char scr;
-
- int use_dma;
- /*
- * Some bits in registers are cleared on a read, so they must
- * be saved whenever the register is read but the bits will not
- * be immediately processed.
- */
- unsigned int lsr_break_flag;
- unsigned char msr_saved_flags;
- char name[20];
- unsigned long port_activity;
- u32 context_loss_cnt;
- u32 errata;
- u8 wakeups_enabled;
-
- struct pm_qos_request pm_qos_request;
- u32 latency;
- u32 calc_latency;
- struct work_struct qos_work;
-};
-
#endif /* __OMAP_SERIAL_H__ */
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
index c34785dca92b..ec536e4e36c9 100644
--- a/arch/ia64/hp/sim/simserial.c
+++ b/arch/ia64/hp/sim/simserial.c
@@ -338,7 +338,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
}
}
@@ -545,6 +545,7 @@ static int __init simrs_init(void)
/* the port is imaginary */
printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq);
+ tty_port_link_device(&state->port, hp_simserial_driver, 0);
retval = tty_register_driver(hp_simserial_driver);
if (retval) {
printk(KERN_ERR "Couldn't register simserial driver\n");
diff --git a/arch/m68k/emu/nfcon.c b/arch/m68k/emu/nfcon.c
index 8db25e806947..16d170f53bfd 100644
--- a/arch/m68k/emu/nfcon.c
+++ b/arch/m68k/emu/nfcon.c
@@ -19,6 +19,7 @@
#include <asm/natfeat.h>
static int stderr_id;
+static struct tty_port nfcon_tty_port;
static struct tty_driver *nfcon_tty_driver;
static void nfputs(const char *str, unsigned int count)
@@ -119,6 +120,8 @@ static int __init nfcon_init(void)
{
int res;
+ tty_port_init(&nfcon_tty_port);
+
stderr_id = nf_get_id("NF_STDERR");
if (!stderr_id)
return -ENODEV;
@@ -135,6 +138,7 @@ static int __init nfcon_init(void)
nfcon_tty_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(nfcon_tty_driver, &nfcon_tty_ops);
+ tty_port_link_device(&nfcon_tty_port, nfcon_tty_driver, 0);
res = tty_register_driver(nfcon_tty_driver);
if (res) {
pr_err("failed to register nfcon tty driver\n");
diff --git a/arch/mips/cavium-octeon/serial.c b/arch/mips/cavium-octeon/serial.c
index 138b2216b4f8..569f41bdcc46 100644
--- a/arch/mips/cavium-octeon/serial.c
+++ b/arch/mips/cavium-octeon/serial.c
@@ -47,40 +47,40 @@ static int __devinit octeon_serial_probe(struct platform_device *pdev)
{
int irq, res;
struct resource *res_mem;
- struct uart_port port;
+ struct uart_8250_port up;
/* All adaptors have an irq. */
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
- memset(&port, 0, sizeof(port));
+ memset(&up, 0, sizeof(up));
- port.flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
- port.type = PORT_OCTEON;
- port.iotype = UPIO_MEM;
- port.regshift = 3;
- port.dev = &pdev->dev;
+ up.port.flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
+ up.port.type = PORT_OCTEON;
+ up.port.iotype = UPIO_MEM;
+ up.port.regshift = 3;
+ up.port.dev = &pdev->dev;
if (octeon_is_simulation())
/* Make simulator output fast*/
- port.uartclk = 115200 * 16;
+ up.port.uartclk = 115200 * 16;
else
- port.uartclk = octeon_get_io_clock_rate();
+ up.port.uartclk = octeon_get_io_clock_rate();
- port.serial_in = octeon_serial_in;
- port.serial_out = octeon_serial_out;
- port.irq = irq;
+ up.port.serial_in = octeon_serial_in;
+ up.port.serial_out = octeon_serial_out;
+ up.port.irq = irq;
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res_mem == NULL) {
dev_err(&pdev->dev, "found no memory resource\n");
return -ENXIO;
}
- port.mapbase = res_mem->start;
- port.membase = ioremap(res_mem->start, resource_size(res_mem));
+ up.port.mapbase = res_mem->start;
+ up.port.membase = ioremap(res_mem->start, resource_size(res_mem));
- res = serial8250_register_port(&port);
+ res = serial8250_register_8250_port(&up);
return res >= 0 ? 0 : res;
}
diff --git a/arch/mips/sni/a20r.c b/arch/mips/sni/a20r.c
index c48194c3073b..b2d4f492d782 100644
--- a/arch/mips/sni/a20r.c
+++ b/arch/mips/sni/a20r.c
@@ -133,6 +133,38 @@ static struct platform_device sc26xx_pdev = {
}
};
+#warning "Please try migrate to use new driver SCCNXP and report the status" \
+ "in the linux-serial mailing list."
+
+/* The code bellow is a replacement of SC26XX to SCCNXP */
+#if 0
+#include <linux/platform_data/sccnxp.h>
+
+static struct sccnxp_pdata sccnxp_data = {
+ .reg_shift = 2,
+ .frequency = 3686400,
+ .mctrl_cfg[0] = MCTRL_SIG(DTR_OP, LINE_OP7) |
+ MCTRL_SIG(RTS_OP, LINE_OP3) |
+ MCTRL_SIG(DSR_IP, LINE_IP5) |
+ MCTRL_SIG(DCD_IP, LINE_IP6),
+ .mctrl_cfg[1] = MCTRL_SIG(DTR_OP, LINE_OP2) |
+ MCTRL_SIG(RTS_OP, LINE_OP1) |
+ MCTRL_SIG(DSR_IP, LINE_IP0) |
+ MCTRL_SIG(CTS_IP, LINE_IP1) |
+ MCTRL_SIG(DCD_IP, LINE_IP2) |
+ MCTRL_SIG(RNG_IP, LINE_IP3),
+};
+
+static struct platform_device sc2681_pdev = {
+ .name = "sc2681",
+ .resource = sc2xxx_rsrc,
+ .num_resources = ARRAY_SIZE(sc2xxx_rsrc),
+ .dev = {
+ .platform_data = &sccnxp_data,
+ },
+};
+#endif
+
static u32 a20r_ack_hwint(void)
{
u32 status = read_c0_status();
diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c
index 47341aa208f2..88238638aee6 100644
--- a/arch/parisc/kernel/pdc_cons.c
+++ b/arch/parisc/kernel/pdc_cons.c
@@ -202,6 +202,7 @@ static int __init pdc_console_tty_driver_init(void)
pdc_console_tty_driver->flags = TTY_DRIVER_REAL_RAW |
TTY_DRIVER_RESET_TERMIOS;
tty_set_operations(pdc_console_tty_driver, &pdc_console_tty_ops);
+ tty_port_link_device(&tty_port, pdc_console_tty_driver, 0);
err = tty_register_driver(pdc_console_tty_driver);
if (err) {
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index bbaf2c59830a..457475f98414 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -409,7 +409,8 @@ int setup_one_line(struct line *lines, int n, char *init,
line->valid = 1;
err = parse_chan_pair(new, line, n, opts, error_out);
if (!err) {
- struct device *d = tty_register_device(driver, n, NULL);
+ struct device *d = tty_port_register_device(&line->port,
+ driver, n, NULL);
if (IS_ERR(d)) {
*error_out = "Failed to register device";
err = PTR_ERR(d);
diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c
index f9726f6afdf1..2cd3d3a3400b 100644
--- a/arch/xtensa/platforms/iss/console.c
+++ b/arch/xtensa/platforms/iss/console.c
@@ -223,6 +223,7 @@ int __init rs_init(void)
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &serial_ops);
+ tty_port_link_device(&serial_port, serial_driver, 0);
if (tty_register_driver(serial_driver))
panic("Couldn't register serial driver\n");
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index 12172a6a95c4..0bc8a6a6a148 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -58,7 +58,7 @@ static int ath_wakeup_ar3k(struct tty_struct *tty)
return status;
/* Disable Automatic RTSCTS */
- memcpy(&ktermios, tty->termios, sizeof(ktermios));
+ ktermios = tty->termios;
ktermios.c_cflag &= ~CRTSCTS;
tty_set_termios(tty, &ktermios);
diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c
index 1d82d5838f0c..164544afd680 100644
--- a/drivers/char/mwave/mwavedd.c
+++ b/drivers/char/mwave/mwavedd.c
@@ -430,7 +430,7 @@ static ssize_t mwave_write(struct file *file, const char __user *buf,
static int register_serial_portandirq(unsigned int port, int irq)
{
- struct uart_port uart;
+ struct uart_8250_port uart;
switch ( port ) {
case 0x3f8:
@@ -462,14 +462,14 @@ static int register_serial_portandirq(unsigned int port, int irq)
} /* switch */
/* irq is okay */
- memset(&uart, 0, sizeof(struct uart_port));
+ memset(&uart, 0, sizeof(uart));
- uart.uartclk = 1843200;
- uart.iobase = port;
- uart.irq = irq;
- uart.iotype = UPIO_PORT;
- uart.flags = UPF_SHARE_IRQ;
- return serial8250_register_port(&uart);
+ uart.port.uartclk = 1843200;
+ uart.port.iobase = port;
+ uart.port.irq = irq;
+ uart.port.iotype = UPIO_PORT;
+ uart.port.flags = UPF_SHARE_IRQ;
+ return serial8250_register_8250_port(&uart);
}
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index a6b8ddea2227..21721d25e388 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -1058,7 +1058,7 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty)
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
- if (tty && (info->port.flags & ASYNC_CTS_FLOW)) {
+ if (tty && tty_port_cts_enabled(&info->port)) {
if (tty->hw_stopped) {
if (info->serial_signals & SerialSignal_CTS) {
if (debug_level >= DEBUG_LEVEL_ISR)
@@ -1350,7 +1350,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
/* TODO:disable interrupts instead of reset to preserve signal states */
reset_device(info);
- if (!tty || tty->termios->c_cflag & HUPCL) {
+ if (!tty || tty->termios.c_cflag & HUPCL) {
info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
set_signals(info);
}
@@ -1391,7 +1391,7 @@ static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI);
get_signals(info);
- if (info->netcount || (tty && (tty->termios->c_cflag & CREAD)))
+ if (info->netcount || (tty && (tty->termios.c_cflag & CREAD)))
rx_start(info);
spin_unlock_irqrestore(&info->lock,flags);
@@ -1404,14 +1404,14 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
unsigned cflag;
int bits_per_char;
- if (!tty || !tty->termios)
+ if (!tty)
return;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_change_params(%s)\n",
__FILE__,__LINE__, info->device_name );
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
/* if B0 rate (hangup) specified then negate DTR and RTS */
/* otherwise assert DTR and RTS */
@@ -1734,7 +1734,7 @@ static void mgslpc_throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
mgslpc_send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals &= ~SerialSignal_RTS;
set_signals(info);
@@ -1763,7 +1763,7 @@ static void mgslpc_unthrottle(struct tty_struct * tty)
mgslpc_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals |= SerialSignal_RTS;
set_signals(info);
@@ -2299,8 +2299,8 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
tty->driver->name );
/* just return if nothing has changed */
- if ((tty->termios->c_cflag == old_termios->c_cflag)
- && (RELEVANT_IFLAG(tty->termios->c_iflag)
+ if ((tty->termios.c_cflag == old_termios->c_cflag)
+ && (RELEVANT_IFLAG(tty->termios.c_iflag)
== RELEVANT_IFLAG(old_termios->c_iflag)))
return;
@@ -2308,7 +2308,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
/* Handle transition to B0 status */
if (old_termios->c_cflag & CBAUD &&
- !(tty->termios->c_cflag & CBAUD)) {
+ !(tty->termios.c_cflag & CBAUD)) {
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
spin_lock_irqsave(&info->lock,flags);
set_signals(info);
@@ -2317,9 +2317,9 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
/* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) &&
- tty->termios->c_cflag & CBAUD) {
+ tty->termios.c_cflag & CBAUD) {
info->serial_signals |= SerialSignal_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
+ if (!(tty->termios.c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
info->serial_signals |= SerialSignal_RTS;
}
@@ -2330,7 +2330,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
/* Handle turning off CRTSCTS */
if (old_termios->c_cflag & CRTSCTS &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
tx_release(tty);
}
@@ -2737,6 +2737,8 @@ static void mgslpc_add_device(MGSLPC_INFO *info)
#if SYNCLINK_GENERIC_HDLC
hdlcdev_init(info);
#endif
+ tty_port_register_device(&info->port, serial_driver, info->line,
+ &info->p_dev->dev);
}
static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
@@ -2750,6 +2752,7 @@ static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
last->next_device = info->next_device;
else
mgslpc_device_list = info->next_device;
+ tty_unregister_device(serial_driver, info->line);
#if SYNCLINK_GENERIC_HDLC
hdlcdev_exit(info);
#endif
@@ -2804,77 +2807,63 @@ static const struct tty_operations mgslpc_ops = {
.proc_fops = &mgslpc_proc_fops,
};
-static void synclink_cs_cleanup(void)
+static int __init synclink_cs_init(void)
{
int rc;
- while(mgslpc_device_list)
- mgslpc_remove_device(mgslpc_device_list);
-
- if (serial_driver) {
- if ((rc = tty_unregister_driver(serial_driver)))
- printk("%s(%d) failed to unregister tty driver err=%d\n",
- __FILE__,__LINE__,rc);
- put_tty_driver(serial_driver);
+ if (break_on_load) {
+ mgslpc_get_text_ptr();
+ BREAKPOINT();
}
- pcmcia_unregister_driver(&mgslpc_driver);
-}
-
-static int __init synclink_cs_init(void)
-{
- int rc;
-
- if (break_on_load) {
- mgslpc_get_text_ptr();
- BREAKPOINT();
- }
-
- if ((rc = pcmcia_register_driver(&mgslpc_driver)) < 0)
- return rc;
-
- serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT);
- if (!serial_driver) {
- rc = -ENOMEM;
- goto error;
- }
+ serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT,
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV);
+ if (IS_ERR(serial_driver)) {
+ rc = PTR_ERR(serial_driver);
+ goto err;
+ }
- /* Initialize the tty_driver structure */
-
- serial_driver->driver_name = "synclink_cs";
- serial_driver->name = "ttySLP";
- serial_driver->major = ttymajor;
- serial_driver->minor_start = 64;
- serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver->subtype = SERIAL_TYPE_NORMAL;
- serial_driver->init_termios = tty_std_termios;
- serial_driver->init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(serial_driver, &mgslpc_ops);
-
- if ((rc = tty_register_driver(serial_driver)) < 0) {
- printk("%s(%d):Couldn't register serial driver\n",
- __FILE__,__LINE__);
- put_tty_driver(serial_driver);
- serial_driver = NULL;
- goto error;
- }
+ /* Initialize the tty_driver structure */
+ serial_driver->driver_name = "synclink_cs";
+ serial_driver->name = "ttySLP";
+ serial_driver->major = ttymajor;
+ serial_driver->minor_start = 64;
+ serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ serial_driver->subtype = SERIAL_TYPE_NORMAL;
+ serial_driver->init_termios = tty_std_termios;
+ serial_driver->init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ tty_set_operations(serial_driver, &mgslpc_ops);
+
+ rc = tty_register_driver(serial_driver);
+ if (rc < 0) {
+ printk(KERN_ERR "%s(%d):Couldn't register serial driver\n",
+ __FILE__, __LINE__);
+ goto err_put_tty;
+ }
- printk("%s %s, tty major#%d\n",
- driver_name, driver_version,
- serial_driver->major);
+ rc = pcmcia_register_driver(&mgslpc_driver);
+ if (rc < 0)
+ goto err_unreg_tty;
- return 0;
+ printk(KERN_INFO "%s %s, tty major#%d\n", driver_name, driver_version,
+ serial_driver->major);
-error:
- synclink_cs_cleanup();
- return rc;
+ return 0;
+err_unreg_tty:
+ tty_unregister_driver(serial_driver);
+err_put_tty:
+ put_tty_driver(serial_driver);
+err:
+ return rc;
}
static void __exit synclink_cs_exit(void)
{
- synclink_cs_cleanup();
+ pcmcia_unregister_driver(&mgslpc_driver);
+ tty_unregister_driver(serial_driver);
+ put_tty_driver(serial_driver);
}
module_init(synclink_cs_init);
diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
index 46b77ede84c0..af98f6d6509b 100644
--- a/drivers/char/ttyprintk.c
+++ b/drivers/char/ttyprintk.c
@@ -67,7 +67,7 @@ static int tpk_printk(const unsigned char *buf, int count)
tmp[tpk_curr + 1] = '\0';
printk(KERN_INFO "%s%s", tpk_tag, tmp);
tpk_curr = 0;
- if (buf[i + 1] == '\n')
+ if ((i + 1) < count && buf[i + 1] == '\n')
i++;
break;
case '\n':
@@ -178,11 +178,17 @@ static struct tty_driver *ttyprintk_driver;
static int __init ttyprintk_init(void)
{
int ret = -ENOMEM;
- void *rp;
- ttyprintk_driver = alloc_tty_driver(1);
- if (!ttyprintk_driver)
- return ret;
+ tty_port_init(&tpk_port.port);
+ tpk_port.port.ops = &null_ops;
+ mutex_init(&tpk_port.port_write_mutex);
+
+ ttyprintk_driver = tty_alloc_driver(1,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_UNNUMBERED_NODE);
+ if (IS_ERR(ttyprintk_driver))
+ return PTR_ERR(ttyprintk_driver);
ttyprintk_driver->driver_name = "ttyprintk";
ttyprintk_driver->name = "ttyprintk";
@@ -191,9 +197,8 @@ static int __init ttyprintk_init(void)
ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
ttyprintk_driver->init_termios = tty_std_termios;
ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
- ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
- TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+ tty_port_link_device(&tpk_port.port, ttyprintk_driver, 0);
ret = tty_register_driver(ttyprintk_driver);
if (ret < 0) {
@@ -201,22 +206,10 @@ static int __init ttyprintk_init(void)
goto error;
}
- /* create our unnumbered device */
- rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
- ttyprintk_driver->name);
- if (IS_ERR(rp)) {
- printk(KERN_ERR "Couldn't create ttyprintk device\n");
- ret = PTR_ERR(rp);
- goto error;
- }
-
- tty_port_init(&tpk_port.port);
- tpk_port.port.ops = &null_ops;
- mutex_init(&tpk_port.port_write_mutex);
-
return 0;
error:
+ tty_unregister_driver(ttyprintk_driver);
put_tty_driver(ttyprintk_driver);
ttyprintk_driver = NULL;
return ret;
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 38c4bd87b2c9..c679867c2ccd 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -234,7 +234,8 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
mp->minor = minor;
- dev = tty_register_device(capinc_tty_driver, minor, NULL);
+ dev = tty_port_register_device(&mp->port, capinc_tty_driver, minor,
+ NULL);
if (IS_ERR(dev))
goto err_out2;
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index a6d9fd2858f7..67abf3ff45e8 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -446,8 +446,8 @@ static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
goto out;
}
- iflag = tty->termios->c_iflag;
- cflag = tty->termios->c_cflag;
+ iflag = tty->termios.c_iflag;
+ cflag = tty->termios.c_cflag;
old_cflag = old ? old->c_cflag : cflag;
gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x",
cs->minor_index, iflag, cflag, old_cflag);
@@ -524,7 +524,8 @@ void gigaset_if_init(struct cardstate *cs)
tasklet_init(&cs->if_wake_tasklet, if_wake, (unsigned long) cs);
mutex_lock(&cs->mutex);
- cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL);
+ cs->tty_dev = tty_port_register_device(&cs->port, drv->tty,
+ cs->minor_index, NULL);
if (!IS_ERR(cs->tty_dev))
dev_set_drvdata(cs->tty_dev, cs);
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 7bc50670d7d9..b817809f763c 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1009,15 +1009,15 @@ isdn_tty_change_speed(modem_info *info)
quot;
int i;
- if (!port->tty || !port->tty->termios)
+ if (!port->tty)
return;
- cflag = port->tty->termios->c_cflag;
+ cflag = port->tty->termios.c_cflag;
quot = i = cflag & CBAUD;
if (i & CBAUDEX) {
i &= ~CBAUDEX;
if (i < 1 || i > 2)
- port->tty->termios->c_cflag &= ~CBAUDEX;
+ port->tty->termios.c_cflag &= ~CBAUDEX;
else
i += 15;
}
@@ -1097,7 +1097,7 @@ isdn_tty_shutdown(modem_info *info)
#endif
isdn_unlock_drivers();
info->msr &= ~UART_MSR_RI;
- if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
+ if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) {
info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
isdn_tty_modem_reset_regs(info, 0);
@@ -1469,13 +1469,13 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
if (!old_termios)
isdn_tty_change_speed(info);
else {
- if (tty->termios->c_cflag == old_termios->c_cflag &&
- tty->termios->c_ispeed == old_termios->c_ispeed &&
- tty->termios->c_ospeed == old_termios->c_ospeed)
+ if (tty->termios.c_cflag == old_termios->c_cflag &&
+ tty->termios.c_ispeed == old_termios->c_ispeed &&
+ tty->termios.c_ospeed == old_termios->c_ospeed)
return;
isdn_tty_change_speed(info);
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS))
+ !(tty->termios.c_cflag & CRTSCTS))
tty->hw_stopped = 0;
}
}
@@ -1486,6 +1486,18 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* ------------------------------------------------------------
*/
+static int isdn_tty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ modem_info *info = &dev->mdm.info[tty->index];
+
+ if (isdn_tty_paranoia_check(info, tty->name, __func__))
+ return -ENODEV;
+
+ tty->driver_data = info;
+
+ return tty_port_install(&info->port, driver, tty);
+}
+
/*
* This routine is called whenever a serial port is opened. It
* enables interrupts for a serial port, linking in its async structure into
@@ -1495,22 +1507,16 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
static int
isdn_tty_open(struct tty_struct *tty, struct file *filp)
{
- struct tty_port *port;
- modem_info *info;
+ modem_info *info = tty->driver_data;
+ struct tty_port *port = &info->port;
int retval;
- info = &dev->mdm.info[tty->index];
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
- return -ENODEV;
- port = &info->port;
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
port->count);
#endif
port->count++;
- tty->driver_data = info;
port->tty = tty;
- tty->port = port;
/*
* Start up serial port
*/
@@ -1738,6 +1744,7 @@ modem_write_profile(atemu *m)
}
static const struct tty_operations modem_ops = {
+ .install = isdn_tty_install,
.open = isdn_tty_open,
.close = isdn_tty_close,
.write = isdn_tty_write,
@@ -1782,7 +1789,7 @@ isdn_tty_modem_init(void)
m->tty_modem->subtype = SERIAL_TYPE_NORMAL;
m->tty_modem->init_termios = tty_std_termios;
m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ m->tty_modem->flags = TTY_DRIVER_REAL_RAW;
m->tty_modem->driver_name = "isdn_tty";
tty_set_operations(m->tty_modem, &modem_ops);
retval = tty_register_driver(m->tty_modem);
diff --git a/drivers/misc/ibmasm/uart.c b/drivers/misc/ibmasm/uart.c
index 1dcb9ae1905a..01e2b0d7e590 100644
--- a/drivers/misc/ibmasm/uart.c
+++ b/drivers/misc/ibmasm/uart.c
@@ -33,7 +33,7 @@
void ibmasm_register_uart(struct service_processor *sp)
{
- struct uart_port uport;
+ struct uart_8250_port uart;
void __iomem *iomem_base;
iomem_base = sp->base_address + SCOUT_COM_B_BASE;
@@ -47,14 +47,14 @@ void ibmasm_register_uart(struct service_processor *sp)
return;
}
- memset(&uport, 0, sizeof(struct uart_port));
- uport.irq = sp->irq;
- uport.uartclk = 3686400;
- uport.flags = UPF_SHARE_IRQ;
- uport.iotype = UPIO_MEM;
- uport.membase = iomem_base;
+ memset(&uart, 0, sizeof(uart));
+ uart.port.irq = sp->irq;
+ uart.port.uartclk = 3686400;
+ uart.port.flags = UPF_SHARE_IRQ;
+ uart.port.iotype = UPIO_MEM;
+ uart.port.membase = iomem_base;
- sp->serial_line = serial8250_register_port(&uport);
+ sp->serial_line = serial8250_register_8250_port(&uart);
if (sp->serial_line < 0) {
dev_err(sp->dev, "Failed to register serial port\n");
return;
diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index b7eb545394b1..4999b34b7a60 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -60,7 +60,7 @@ struct pti_tty {
};
struct pti_dev {
- struct tty_port port;
+ struct tty_port port[PTITTY_MINOR_NUM];
unsigned long pti_addr;
unsigned long aperture_base;
void __iomem *pti_ioaddr;
@@ -76,7 +76,7 @@ struct pti_dev {
*/
static DEFINE_MUTEX(alloclock);
-static struct pci_device_id pci_ids[] __devinitconst = {
+static const struct pci_device_id pci_ids[] __devinitconst = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)},
{0}
};
@@ -393,25 +393,6 @@ void pti_writedata(struct pti_masterchannel *mc, u8 *buf, int count)
}
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.
@@ -446,7 +427,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp)
* also removes a locking requirement for the actual write
* procedure.
*/
- return tty_port_open(&drv_data->port, tty, filp);
+ return tty_port_open(tty->port, tty, filp);
}
/**
@@ -462,7 +443,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp)
*/
static void pti_tty_driver_close(struct tty_struct *tty, struct file *filp)
{
- tty_port_close(&drv_data->port, tty, filp);
+ tty_port_close(tty->port, tty, filp);
}
/**
@@ -818,6 +799,7 @@ static const struct tty_port_operations tty_port_ops = {
static int __devinit pti_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
+ unsigned int a;
int retval = -EINVAL;
int pci_bar = 1;
@@ -830,7 +812,7 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
__func__, __LINE__);
pr_err("%s(%d): Error value returned: %d\n",
__func__, __LINE__, retval);
- return retval;
+ goto err;
}
retval = pci_enable_device(pdev);
@@ -838,17 +820,16 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
dev_err(&pdev->dev,
"%s: pci_enable_device() returned error %d\n",
__func__, retval);
- return retval;
+ goto err_unreg_misc;
}
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;
+ goto err_disable_pci;
}
drv_data->pti_addr = pci_resource_start(pdev, pci_bar);
@@ -857,33 +838,65 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
dev_err(&pdev->dev,
"%s(%d): pci_request_region() returned error %d\n",
__func__, __LINE__, retval);
- kfree(drv_data);
- return retval;
+ goto err_free_dd;
}
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;
+ goto err_rel_reg;
}
pci_set_drvdata(pdev, drv_data);
- tty_port_init(&drv_data->port);
- drv_data->port.ops = &tty_port_ops;
+ for (a = 0; a < PTITTY_MINOR_NUM; a++) {
+ struct tty_port *port = &drv_data->port[a];
+ tty_port_init(port);
+ port->ops = &tty_port_ops;
- tty_register_device(pti_tty_driver, 0, &pdev->dev);
- tty_register_device(pti_tty_driver, 1, &pdev->dev);
+ tty_port_register_device(port, pti_tty_driver, a, &pdev->dev);
+ }
register_console(&pti_console);
+ return 0;
+err_rel_reg:
+ pci_release_region(pdev, pci_bar);
+err_free_dd:
+ kfree(drv_data);
+err_disable_pci:
+ pci_disable_device(pdev);
+err_unreg_misc:
+ misc_deregister(&pti_char_driver);
+err:
return retval;
}
+/**
+ * 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 = pci_get_drvdata(pdev);
+
+ unregister_console(&pti_console);
+
+ tty_unregister_device(pti_tty_driver, 0);
+ tty_unregister_device(pti_tty_driver, 1);
+
+ iounmap(drv_data->pti_ioaddr);
+ pci_set_drvdata(pdev, NULL);
+ kfree(drv_data);
+ pci_release_region(pdev, 1);
+ pci_disable_device(pdev);
+
+ misc_deregister(&pti_char_driver);
+}
+
static struct pci_driver pti_pci_driver = {
.name = PCINAME,
.id_table = pci_ids,
@@ -933,25 +946,24 @@ static int __init pti_init(void)
pr_err("%s(%d): Error value returned: %d\n",
__func__, __LINE__, retval);
- pti_tty_driver = NULL;
- return retval;
+ goto put_tty;
}
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;
+ goto unreg_tty;
}
+ return 0;
+unreg_tty:
+ tty_unregister_driver(pti_tty_driver);
+put_tty:
+ put_tty_driver(pti_tty_driver);
+ pti_tty_driver = NULL;
return retval;
}
@@ -960,31 +972,9 @@ static int __init pti_init(void)
*/
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);
- }
-
+ tty_unregister_driver(pti_tty_driver);
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;
+ put_tty_driver(pti_tty_driver);
}
module_init(pti_init);
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 5a2cbfac66d2..d2339ea37815 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -518,7 +518,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
if (status & UART_MSR_DCTS) {
port->icount.cts++;
tty = tty_port_tty_get(&port->port);
- if (tty && (tty->termios->c_cflag & CRTSCTS)) {
+ if (tty && (tty->termios.c_cflag & CRTSCTS)) {
int cts = (status & UART_MSR_CTS);
if (tty->hw_stopped) {
if (cts) {
@@ -671,12 +671,12 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE;
port->mctrl = TIOCM_OUT2;
- sdio_uart_change_speed(port, tty->termios, NULL);
+ sdio_uart_change_speed(port, &tty->termios, NULL);
- if (tty->termios->c_cflag & CBAUD)
+ if (tty->termios.c_cflag & CBAUD)
sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
tty->hw_stopped = 1;
@@ -850,7 +850,7 @@ static void sdio_uart_throttle(struct tty_struct *tty)
{
struct sdio_uart_port *port = tty->driver_data;
- if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
+ if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS))
return;
if (sdio_uart_claim_func(port) != 0)
@@ -861,7 +861,7 @@ static void sdio_uart_throttle(struct tty_struct *tty)
sdio_uart_start_tx(port);
}
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
sdio_uart_clear_mctrl(port, TIOCM_RTS);
sdio_uart_irq(port->func);
@@ -872,7 +872,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
{
struct sdio_uart_port *port = tty->driver_data;
- if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
+ if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS))
return;
if (sdio_uart_claim_func(port) != 0)
@@ -887,7 +887,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
}
}
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
sdio_uart_set_mctrl(port, TIOCM_RTS);
sdio_uart_irq(port->func);
@@ -898,12 +898,12 @@ static void sdio_uart_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
struct sdio_uart_port *port = tty->driver_data;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = tty->termios.c_cflag;
if (sdio_uart_claim_func(port) != 0)
return;
- sdio_uart_change_speed(port, tty->termios, old_termios);
+ sdio_uart_change_speed(port, &tty->termios, old_termios);
/* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
@@ -1132,8 +1132,8 @@ static int sdio_uart_probe(struct sdio_func *func,
kfree(port);
} else {
struct device *dev;
- dev = tty_register_device(sdio_uart_tty_driver,
- port->index, &func->dev);
+ dev = tty_port_register_device(&port->port,
+ sdio_uart_tty_driver, port->index, &func->dev);
if (IS_ERR(dev)) {
sdio_uart_port_remove(port);
ret = PTR_ERR(dev);
diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c
index b5ba3084c7fc..3e5519a0acc7 100644
--- a/drivers/net/ethernet/sgi/ioc3-eth.c
+++ b/drivers/net/ethernet/sgi/ioc3-eth.c
@@ -1147,15 +1147,17 @@ static void __devinit ioc3_8250_register(struct ioc3_uartregs __iomem *uart)
{
#define COSMISC_CONSTANT 6
- struct uart_port port = {
- .irq = 0,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 0,
- .uartclk = (22000000 << 1) / COSMISC_CONSTANT,
-
- .membase = (unsigned char __iomem *) uart,
- .mapbase = (unsigned long) uart,
+ struct uart_8250_port port = {
+ .port = {
+ .irq = 0,
+ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 0,
+ .uartclk = (22000000 << 1) / COSMISC_CONSTANT,
+
+ .membase = (unsigned char __iomem *) uart,
+ .mapbase = (unsigned long) uart,
+ }
};
unsigned char lcr;
@@ -1164,7 +1166,7 @@ static void __devinit ioc3_8250_register(struct ioc3_uartregs __iomem *uart)
uart->iu_scr = COSMISC_CONSTANT,
uart->iu_lcr = lcr;
uart->iu_lcr;
- serial8250_register_port(&port);
+ serial8250_register_8250_port(&port);
}
static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index 3352b2443e58..30087ca23a0f 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -124,8 +124,8 @@ static int irtty_change_speed(struct sir_dev *dev, unsigned speed)
tty = priv->tty;
mutex_lock(&tty->termios_mutex);
- old_termios = *(tty->termios);
- cflag = tty->termios->c_cflag;
+ old_termios = tty->termios;
+ cflag = tty->termios.c_cflag;
tty_encode_baud_rate(tty, speed, speed);
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old_termios);
@@ -281,15 +281,15 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
int cflag;
mutex_lock(&tty->termios_mutex);
- old_termios = *(tty->termios);
- cflag = tty->termios->c_cflag;
+ old_termios = tty->termios;
+ cflag = tty->termios.c_cflag;
if (stop)
cflag &= ~CREAD;
else
cflag |= CREAD;
- tty->termios->c_cflag = cflag;
+ tty->termios.c_cflag = cflag;
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old_termios);
mutex_unlock(&tty->termios_mutex);
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 62f30b46fa42..605a4baa9b7b 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -1107,7 +1107,6 @@ static void _hso_serial_set_termios(struct tty_struct *tty,
struct ktermios *old)
{
struct hso_serial *serial = tty->driver_data;
- struct ktermios *termios;
if (!serial) {
printk(KERN_ERR "%s: no tty structures", __func__);
@@ -1119,16 +1118,15 @@ static void _hso_serial_set_termios(struct tty_struct *tty,
/*
* Fix up unsupported bits
*/
- termios = tty->termios;
- termios->c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */
+ tty->termios.c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */
- termios->c_cflag &=
+ tty->termios.c_cflag &=
~(CSIZE /* no size */
| PARENB /* disable parity bit */
| CBAUD /* clear current baud rate */
| CBAUDEX); /* clear current buad rate */
- termios->c_cflag |= CS8; /* character size 8 bits */
+ tty->termios.c_cflag |= CS8; /* character size 8 bits */
/* baud rate 115200 */
tty_encode_baud_rate(tty, 115200, 115200);
@@ -1425,14 +1423,14 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
if (old)
D5("Termios called with: cflags new[%d] - old[%d]",
- tty->termios->c_cflag, old->c_cflag);
+ tty->termios.c_cflag, old->c_cflag);
/* the actual setup */
spin_lock_irqsave(&serial->serial_lock, flags);
if (serial->port.count)
_hso_serial_set_termios(tty, old);
else
- tty->termios = old;
+ tty->termios = *old;
spin_unlock_irqrestore(&serial->serial_lock, flags);
/* done */
@@ -2289,9 +2287,11 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
if (minor < 0)
goto exit;
+ tty_port_init(&serial->port);
+
/* register our minor number */
- serial->parent->dev = tty_register_device(tty_drv, minor,
- &serial->parent->interface->dev);
+ serial->parent->dev = tty_port_register_device(&serial->port, tty_drv,
+ minor, &serial->parent->interface->dev);
dev = serial->parent->dev;
dev_set_drvdata(dev, serial->parent);
i = device_create_file(dev, &dev_attr_hsotype);
@@ -2300,7 +2300,6 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
serial->minor = minor;
serial->magic = HSO_SERIAL_MAGIC;
spin_lock_init(&serial->serial_lock);
- tty_port_init(&serial->port);
serial->num_rx_urbs = num_urbs;
/* RX, allocate urb and initialize */
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
index 5d6de380e42b..352f96180bc7 100644
--- a/drivers/parport/parport_gsc.c
+++ b/drivers/parport/parport_gsc.c
@@ -271,6 +271,7 @@ struct parport *__devinit parport_gsc_probe_port (unsigned long base,
if (!parport_SPP_supported (p)) {
/* No port. */
kfree (priv);
+ kfree(ops);
return NULL;
}
parport_PS2_supported (p);
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index e9c32274df3f..1631eeaf440e 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -62,6 +62,7 @@ enum parport_pc_pci_cards {
timedia_9079a,
timedia_9079b,
timedia_9079c,
+ wch_ch353_2s1p,
};
/* each element directly indexed from enum list, above */
@@ -145,6 +146,7 @@ static struct parport_pc_pci cards[] __devinitdata = {
/* timedia_9079a */ { 1, { { 2, 3 }, } },
/* timedia_9079b */ { 1, { { 2, 3 }, } },
/* timedia_9079c */ { 1, { { 2, 3 }, } },
+ /* wch_ch353_2s1p*/ { 1, { { 2, -1}, } },
};
static struct pci_device_id parport_serial_pci_tbl[] = {
@@ -243,7 +245,8 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
{ 0x1409, 0x7168, 0x1409, 0xb079, 0, 0, timedia_9079a },
{ 0x1409, 0x7168, 0x1409, 0xc079, 0, 0, timedia_9079b },
{ 0x1409, 0x7168, 0x1409, 0xd079, 0, 0, timedia_9079c },
-
+ /* WCH CARDS */
+ { 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p},
{ 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);
@@ -460,6 +463,12 @@ static struct pciserial_board pci_parport_serial_boards[] __devinitdata = {
.base_baud = 921600,
.uart_offset = 8,
},
+ [wch_ch353_2s1p] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
};
struct parport_serial_private {
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 6c0116d48c74..9ffb6d5f17aa 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -716,10 +716,17 @@ static int raw3215_probe (struct ccw_device *cdev)
static void raw3215_remove (struct ccw_device *cdev)
{
struct raw3215_info *raw;
+ unsigned int line;
ccw_device_set_offline(cdev);
raw = dev_get_drvdata(&cdev->dev);
if (raw) {
+ spin_lock(&raw3215_device_lock);
+ for (line = 0; line < NR_3215; line++)
+ if (raw3215[line] == raw)
+ break;
+ raw3215[line] = NULL;
+ spin_unlock(&raw3215_device_lock);
dev_set_drvdata(&cdev->dev, NULL);
raw3215_free_info(raw);
}
@@ -935,6 +942,19 @@ static int __init con3215_init(void)
console_initcall(con3215_init);
#endif
+static int tty3215_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ struct raw3215_info *raw;
+
+ raw = raw3215[tty->index];
+ if (raw == NULL)
+ return -ENODEV;
+
+ tty->driver_data = raw;
+
+ return tty_port_install(&raw->port, driver, tty);
+}
+
/*
* tty3215_open
*
@@ -942,14 +962,9 @@ console_initcall(con3215_init);
*/
static int tty3215_open(struct tty_struct *tty, struct file * filp)
{
- struct raw3215_info *raw;
+ struct raw3215_info *raw = tty->driver_data;
int retval;
- raw = raw3215[tty->index];
- if (raw == NULL)
- return -ENODEV;
-
- tty->driver_data = raw;
tty_port_tty_set(&raw->port, tty);
tty->low_latency = 0; /* don't use bottom half for pushing chars */
@@ -1110,6 +1125,7 @@ static void tty3215_start(struct tty_struct *tty)
}
static const struct tty_operations tty3215_ops = {
+ .install = tty3215_install,
.open = tty3215_open,
.close = tty3215_close,
.write = tty3215_write,
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index 0792c85baafe..30ec09e3d037 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -567,6 +567,7 @@ sclp_tty_init(void)
driver->init_termios.c_lflag = ISIG | ECHO;
driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(driver, &sclp_ops);
+ tty_port_link_device(&sclp_port, driver, 0);
rc = tty_register_driver(driver);
if (rc) {
put_tty_driver(driver);
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index edfc0fd73dc6..7e60f3d2f3f9 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -691,6 +691,7 @@ static int __init sclp_vt220_tty_init(void)
driver->init_termios = tty_std_termios;
driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(driver, &sclp_vt220_ops);
+ tty_port_link_device(&sclp_vt220_port, driver, 0);
rc = tty_register_driver(driver);
if (rc)
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 1928f3458d10..482ee028f842 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -842,17 +842,14 @@ static struct raw3270_fn tty3270_fn = {
};
/*
- * This routine is called whenever a 3270 tty is opened.
+ * This routine is called whenever a 3270 tty is opened first time.
*/
-static int
-tty3270_open(struct tty_struct *tty, struct file * filp)
+static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct raw3270_view *view;
struct tty3270 *tp;
int i, rc;
- if (tty->count > 1)
- return 0;
/* Check if the tty3270 is already there. */
view = raw3270_find_view(&tty3270_fn,
tty->index + RAW3270_FIRSTMINOR);
@@ -865,7 +862,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
/* why to reassign? */
tty_port_tty_set(&tp->port, tty);
tp->inattr = TF_INPUT;
- return 0;
+ return tty_port_install(&tp->port, driver, tty);
}
if (tty3270_max_index < tty->index + 1)
tty3270_max_index = tty->index + 1;
@@ -895,7 +892,6 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
tty_port_tty_set(&tp->port, tty);
tty->low_latency = 0;
- tty->driver_data = tp;
tty->winsize.ws_row = tp->view.rows - 2;
tty->winsize.ws_col = tp->view.cols;
@@ -915,6 +911,15 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
kbd_ascebc(tp->kbd, tp->view.ascebc);
raw3270_activate_view(&tp->view);
+
+ rc = tty_port_install(&tp->port, driver, tty);
+ if (rc) {
+ raw3270_put_view(&tp->view);
+ return rc;
+ }
+
+ tty->driver_data = tp;
+
return 0;
}
@@ -932,10 +937,17 @@ tty3270_close(struct tty_struct *tty, struct file * filp)
if (tp) {
tty->driver_data = NULL;
tty_port_tty_set(&tp->port, NULL);
- raw3270_put_view(&tp->view);
}
}
+static void tty3270_cleanup(struct tty_struct *tty)
+{
+ struct tty3270 *tp = tty->driver_data;
+
+ if (tp)
+ raw3270_put_view(&tp->view);
+}
+
/*
* We always have room.
*/
@@ -1737,7 +1749,8 @@ static long tty3270_compat_ioctl(struct tty_struct *tty,
#endif
static const struct tty_operations tty3270_ops = {
- .open = tty3270_open,
+ .install = tty3270_install,
+ .cleanup = tty3270_cleanup,
.close = tty3270_close,
.write = tty3270_write,
.put_char = tty3270_put_char,
@@ -1781,7 +1794,7 @@ static int __init tty3270_init(void)
driver->type = TTY_DRIVER_TYPE_SYSTEM;
driver->subtype = SYSTEM_TYPE_TTY;
driver->init_termios = tty_std_termios;
- driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_DYNAMIC_DEV;
+ driver->flags = TTY_DRIVER_RESET_TERMIOS;
tty_set_operations(driver, &tty3270_ops);
ret = tty_register_driver(driver);
if (ret) {
@@ -1800,6 +1813,7 @@ tty3270_exit(void)
driver = tty3270_driver;
tty3270_driver = NULL;
tty_unregister_driver(driver);
+ put_tty_driver(driver);
tty3270_del_views();
}
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 0f51a158ef70..d805eef11915 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -142,4 +142,6 @@ source "drivers/staging/ced1401/Kconfig"
source "drivers/staging/imx-drm/Kconfig"
+source "drivers/staging/dgrp/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index f4b2bc41f1d1..76e2ebd596ff 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -63,3 +63,4 @@ obj-$(CONFIG_ZCACHE2) += ramster/
obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/
obj-$(CONFIG_CED1401) += ced1401/
obj-$(CONFIG_DRM_IMX) += imx-drm/
+obj-$(CONFIG_DGRP) += dgrp/
diff --git a/drivers/staging/dgrp/Kconfig b/drivers/staging/dgrp/Kconfig
new file mode 100644
index 000000000000..39f4bb65ec83
--- /dev/null
+++ b/drivers/staging/dgrp/Kconfig
@@ -0,0 +1,9 @@
+config DGRP
+ tristate "Digi Realport driver"
+ default n
+ depends on SYSFS
+ ---help---
+ Support for Digi Realport devices. These devices allow you to
+ access remote serial ports as if they are local tty devices. This
+ will build the kernel driver, you will still need the userspace
+ component to make your Realport device work.
diff --git a/drivers/staging/dgrp/Makefile b/drivers/staging/dgrp/Makefile
new file mode 100644
index 000000000000..d9c3b88d7162
--- /dev/null
+++ b/drivers/staging/dgrp/Makefile
@@ -0,0 +1,12 @@
+obj-$(CONFIG_DGRP) += dgrp.o
+
+dgrp-y := \
+ dgrp_common.o \
+ dgrp_dpa_ops.o \
+ dgrp_driver.o \
+ dgrp_mon_ops.o \
+ dgrp_net_ops.o \
+ dgrp_ports_ops.o \
+ dgrp_specproc.o \
+ dgrp_tty.o \
+ dgrp_sysfs.o
diff --git a/drivers/staging/dgrp/README b/drivers/staging/dgrp/README
new file mode 100644
index 000000000000..1d8aaee270e8
--- /dev/null
+++ b/drivers/staging/dgrp/README
@@ -0,0 +1,2 @@
+The user space code to work with this driver is located at
+https://github.com/wfp5p/dgrp-utils
diff --git a/drivers/staging/dgrp/TODO b/drivers/staging/dgrp/TODO
new file mode 100644
index 000000000000..3ef2611bc6d7
--- /dev/null
+++ b/drivers/staging/dgrp/TODO
@@ -0,0 +1,13 @@
+- Use configfs for config stuff. This will require changes to the
+ user space code.
+
+- dgrp_send() and dgrp_receive() could use some refactoring
+
+- Don't automatically create CHAN_MAX (64) channel array entries for
+ every device as many devices are going to have much less than 64
+ channels.
+
+- The locking needs to be checked. It seems haphazardly done in most
+ places.
+
+- Check Kconfig dependencies
diff --git a/drivers/staging/dgrp/dgrp_common.c b/drivers/staging/dgrp/dgrp_common.c
new file mode 100644
index 000000000000..fce74e7fb834
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_common.c
@@ -0,0 +1,200 @@
+/*
+ *
+ * Copyright 1999 Digi International (www.digi.com)
+ * James Puzzo <jamesp at digi dot com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ */
+
+/*
+ *
+ * Filename:
+ *
+ * dgrp_common.c
+ *
+ * Description:
+ *
+ * Definitions of global variables and functions which are either
+ * shared by the tty, mon, and net drivers; or which cross them
+ * functionally (like the poller).
+ *
+ * Author:
+ *
+ * James A. Puzzo
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/cred.h>
+
+#include "dgrp_common.h"
+
+/**
+ * dgrp_carrier -- check for carrier change state and act
+ * @ch: struct ch_struct *
+ */
+void dgrp_carrier(struct ch_struct *ch)
+{
+ struct nd_struct *nd;
+
+ int virt_carrier = 0;
+ int phys_carrier = 0;
+
+ /* fix case when the tty has already closed. */
+
+ if (!ch)
+ return;
+ nd = ch->ch_nd;
+ if (!nd)
+ return;
+
+ /*
+ * If we are currently waiting to determine the status of the port,
+ * we don't yet know the state of the modem lines. As a result,
+ * we ignore state changes when we are waiting for the modem lines
+ * to be established. We know, as a result of code in dgrp_net_ops,
+ * that we will be called again immediately following the reception
+ * of the status message with the true modem status flags in it.
+ */
+ if (ch->ch_expect & RR_STATUS)
+ return;
+
+ /*
+ * If CH_HANGUP is set, we gotta keep trying to get all the processes
+ * that have the port open to close the port.
+ * So lets just keep sending a hangup every time we get here.
+ */
+ if ((ch->ch_flag & CH_HANGUP) &&
+ (ch->ch_tun.un_open_count > 0))
+ tty_hangup(ch->ch_tun.un_tty);
+
+ /*
+ * Compute the effective state of both the physical and virtual
+ * senses of carrier.
+ */
+
+ if (ch->ch_s_mlast & DM_CD)
+ phys_carrier = 1;
+
+ if ((ch->ch_s_mlast & DM_CD) ||
+ (ch->ch_digi.digi_flags & DIGI_FORCEDCD) ||
+ (ch->ch_flag & CH_CLOCAL))
+ virt_carrier = 1;
+
+ /*
+ * Test for a VIRTUAL carrier transition to HIGH.
+ *
+ * The CH_HANGUP condition is intended to prevent any action
+ * except for close. As a result, we ignore positive carrier
+ * transitions during CH_HANGUP.
+ */
+ if (((ch->ch_flag & CH_HANGUP) == 0) &&
+ ((ch->ch_flag & CH_VIRT_CD) == 0) &&
+ (virt_carrier == 1)) {
+ /*
+ * When carrier rises, wake any threads waiting
+ * for carrier in the open routine.
+ */
+ nd->nd_tx_work = 1;
+
+ if (waitqueue_active(&ch->ch_flag_wait))
+ wake_up_interruptible(&ch->ch_flag_wait);
+ }
+
+ /*
+ * Test for a PHYSICAL transition to low, so long as we aren't
+ * currently ignoring physical transitions (which is what "virtual
+ * carrier" indicates).
+ *
+ * The transition of the virtual carrier to low really doesn't
+ * matter... it really only means "ignore carrier state", not
+ * "make pretend that carrier is there".
+ */
+ if ((virt_carrier == 0) &&
+ ((ch->ch_flag & CH_PHYS_CD) != 0) &&
+ (phys_carrier == 0)) {
+ /*
+ * When carrier drops:
+ *
+ * Do a Hard Hangup if that is called for.
+ *
+ * Drop carrier on all open units.
+ *
+ * Flush queues, waking up any task waiting in the
+ * line discipline.
+ *
+ * Send a hangup to the control terminal.
+ *
+ * Enable all select calls.
+ */
+
+ nd->nd_tx_work = 1;
+
+ ch->ch_flag &= ~(CH_LOW | CH_EMPTY | CH_DRAIN | CH_INPUT);
+
+ if (waitqueue_active(&ch->ch_flag_wait))
+ wake_up_interruptible(&ch->ch_flag_wait);
+
+ if (ch->ch_tun.un_open_count > 0)
+ tty_hangup(ch->ch_tun.un_tty);
+
+ if (ch->ch_pun.un_open_count > 0)
+ tty_hangup(ch->ch_pun.un_tty);
+ }
+
+ /*
+ * Make sure that our cached values reflect the current reality.
+ */
+ if (virt_carrier == 1)
+ ch->ch_flag |= CH_VIRT_CD;
+ else
+ ch->ch_flag &= ~CH_VIRT_CD;
+
+ if (phys_carrier == 1)
+ ch->ch_flag |= CH_PHYS_CD;
+ else
+ ch->ch_flag &= ~CH_PHYS_CD;
+
+}
+
+/**
+ * dgrp_chk_perm() -- check permissions for net device
+ * @inode: pointer to inode structure for the net communication device
+ * @op: operation to be tested
+ *
+ * The file permissions and ownerships are tested to determine whether
+ * the operation "op" is permitted on the file pointed to by the inode.
+ * Returns 0 if the operation is permitted, -EACCESS otherwise
+ */
+int dgrp_chk_perm(int mode, int op)
+{
+ if (!current_euid())
+ mode >>= 6;
+ else if (in_egroup_p(0))
+ mode >>= 3;
+
+ if ((mode & op & 0007) == op)
+ return 0;
+
+ if (capable(CAP_SYS_ADMIN))
+ return 0;
+
+ return -EACCES;
+}
+
+/* dgrp_chk_perm wrapper for permission call in struct inode_operations */
+int dgrp_inode_permission(struct inode *inode, int op)
+{
+ return dgrp_chk_perm(inode->i_mode, op);
+}
diff --git a/drivers/staging/dgrp/dgrp_common.h b/drivers/staging/dgrp/dgrp_common.h
new file mode 100644
index 000000000000..05ff338471ac
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_common.h
@@ -0,0 +1,208 @@
+/*
+ *
+ * Copyright 1999 Digi International (www.digi.com)
+ * James Puzzo <jamesp at digi dot com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ */
+
+#ifndef __DGRP_COMMON_H
+#define __DGRP_COMMON_H
+
+#define DIGI_VERSION "1.9-29"
+
+#include <linux/fs.h>
+#include <linux/timer.h>
+#include "drp.h"
+
+#define DGRP_TTIME 100
+#define DGRP_RTIME 100
+
+/************************************************************************
+ * All global storage allocation.
+ ************************************************************************/
+
+extern int dgrp_rawreadok; /* Allow raw writing of input */
+extern int dgrp_register_cudevices; /* enable legacy cu devices */
+extern int dgrp_register_prdevices; /* enable transparent print devices */
+extern int dgrp_poll_tick; /* Poll interval - in ms */
+
+extern struct list_head nd_struct_list;
+
+struct dgrp_poll_data {
+ spinlock_t poll_lock;
+ struct timer_list timer;
+ int poll_tick;
+ ulong poll_round; /* Timer rouding factor */
+ long node_active_count;
+};
+
+extern struct dgrp_poll_data dgrp_poll_data;
+extern void dgrp_poll_handler(unsigned long arg);
+
+/* from dgrp_mon_ops.c */
+extern void dgrp_register_mon_hook(struct proc_dir_entry *de);
+
+/* from dgrp_tty.c */
+extern int dgrp_tty_init(struct nd_struct *nd);
+extern void dgrp_tty_uninit(struct nd_struct *nd);
+
+/* from dgrp_ports_ops.c */
+extern void dgrp_register_ports_hook(struct proc_dir_entry *de);
+
+/* from dgrp_net_ops.c */
+extern void dgrp_register_net_hook(struct proc_dir_entry *de);
+
+/* from dgrp_dpa_ops.c */
+extern void dgrp_register_dpa_hook(struct proc_dir_entry *de);
+extern void dgrp_dpa_data(struct nd_struct *, int, u8 *, int);
+
+/* from dgrp_sysfs.c */
+extern void dgrp_create_class_sysfs_files(void);
+extern void dgrp_remove_class_sysfs_files(void);
+
+extern void dgrp_create_node_class_sysfs_files(struct nd_struct *nd);
+extern void dgrp_remove_node_class_sysfs_files(struct nd_struct *nd);
+
+extern void dgrp_create_tty_sysfs(struct un_struct *un, struct device *c);
+extern void dgrp_remove_tty_sysfs(struct device *c);
+
+/* from dgrp_specproc.c */
+/*
+ * The list of DGRP entries with r/w capabilities. These
+ * magic numbers are used for identification purposes.
+ */
+enum {
+ DGRP_CONFIG = 1, /* Configure portservers */
+ DGRP_NETDIR = 2, /* Directory for "net" devices */
+ DGRP_MONDIR = 3, /* Directory for "mon" devices */
+ DGRP_PORTSDIR = 4, /* Directory for "ports" devices */
+ DGRP_INFO = 5, /* Get info. about the running module */
+ DGRP_NODEINFO = 6, /* Get info. about the configured nodes */
+ DGRP_DPADIR = 7, /* Directory for the "dpa" devices */
+};
+
+/*
+ * Directions for proc handlers
+ */
+enum {
+ INBOUND = 1, /* Data being written to kernel */
+ OUTBOUND = 2, /* Data being read from the kernel */
+};
+
+/**
+ * dgrp_proc_entry: structure for dgrp proc dirs
+ * @id: ID number associated with this particular entry. Should be
+ * unique across all of DGRP.
+ * @name: text name associated with the /proc entry
+ * @mode: file access permisssions for the /proc entry
+ * @child: pointer to table describing a subdirectory for this entry
+ * @de: pointer to directory entry for this object once registered. Used
+ * to grab the handle of the object for unregistration
+ * @excl_sem: semaphore to provide exclusive to struct
+ * @excl_cnt: counter of current accesses
+ *
+ * Each entry in a DGRP proc directory is described with a
+ * dgrp_proc_entry structure. A collection of these
+ * entries (in an array) represents the members associated
+ * with a particular /proc directory, and is referred to
+ * as a table. All tables are terminated by an entry with
+ * zeros for every member.
+ */
+struct dgrp_proc_entry {
+ int id; /* Integer identifier */
+ const char *name; /* ASCII identifier */
+ mode_t mode; /* File access permissions */
+ struct dgrp_proc_entry *child; /* Child pointer */
+
+ /* file ops to use, pass NULL to use default */
+ struct file_operations *proc_file_ops;
+
+ struct proc_dir_entry *de; /* proc entry pointer */
+ struct semaphore excl_sem; /* Protects exclusive access var */
+ int excl_cnt; /* Counts number of curr accesses */
+};
+
+extern void dgrp_unregister_proc(void);
+extern void dgrp_register_proc(void);
+
+/*-----------------------------------------------------------------------*
+ *
+ * Declarations for common operations:
+ *
+ * (either used by more than one of net, mon, or tty,
+ * or in interrupt context (i.e. the poller))
+ *
+ *-----------------------------------------------------------------------*/
+
+void dgrp_carrier(struct ch_struct *ch);
+extern int dgrp_inode_permission(struct inode *inode, int op);
+extern int dgrp_chk_perm(int mode, int op);
+
+
+/*
+ * ID manipulation macros (where c1 & c2 are characters, i is
+ * a long integer, and s is a character array of at least three members
+ */
+
+static inline void ID_TO_CHAR(long i, char *s)
+{
+ s[0] = ((i & 0xff00)>>8);
+ s[1] = (i & 0xff);
+ s[2] = 0;
+}
+
+static inline long CHAR_TO_ID(char *s)
+{
+ return ((s[0] & 0xff) << 8) | (s[1] & 0xff);
+}
+
+static inline struct nd_struct *nd_struct_get(long major)
+{
+ struct nd_struct *nd;
+
+ list_for_each_entry(nd, &nd_struct_list, list) {
+ if (major == nd->nd_major)
+ return nd;
+ }
+
+ return NULL;
+}
+
+static inline int nd_struct_add(struct nd_struct *entry)
+{
+ struct nd_struct *ptr;
+
+ ptr = nd_struct_get(entry->nd_major);
+
+ if (ptr)
+ return -EBUSY;
+
+ list_add_tail(&entry->list, &nd_struct_list);
+
+ return 0;
+}
+
+static inline int nd_struct_del(struct nd_struct *entry)
+{
+ struct nd_struct *nd;
+
+ nd = nd_struct_get(entry->nd_major);
+
+ if (!nd)
+ return -ENODEV;
+
+ list_del(&nd->list);
+ return 0;
+}
+
+#endif /* __DGRP_COMMON_H */
diff --git a/drivers/staging/dgrp/dgrp_dpa_ops.c b/drivers/staging/dgrp/dgrp_dpa_ops.c
new file mode 100644
index 000000000000..49e670915e5c
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_dpa_ops.c
@@ -0,0 +1,556 @@
+/*
+ *
+ * Copyright 1999 Digi International (www.digi.com)
+ * James Puzzo <jamesp at digi dot com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ */
+
+/*
+ *
+ * Filename:
+ *
+ * dgrp_dpa_ops.c
+ *
+ * Description:
+ *
+ * Handle the file operations required for the "dpa" devices.
+ * Includes those functions required to register the "dpa" devices
+ * in "/proc".
+ *
+ * Author:
+ *
+ * James A. Puzzo
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/tty.h>
+#include <linux/poll.h>
+#include <linux/cred.h>
+#include <linux/sched.h>
+#include <linux/ratelimit.h>
+#include <asm/unaligned.h>
+
+#include "dgrp_common.h"
+
+/* File operation declarations */
+static int dgrp_dpa_open(struct inode *, struct file *);
+static int dgrp_dpa_release(struct inode *, struct file *);
+static ssize_t dgrp_dpa_read(struct file *, char __user *, size_t, loff_t *);
+static long dgrp_dpa_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg);
+static unsigned int dgrp_dpa_select(struct file *, struct poll_table_struct *);
+
+static const struct file_operations dpa_ops = {
+ .owner = THIS_MODULE,
+ .read = dgrp_dpa_read,
+ .poll = dgrp_dpa_select,
+ .unlocked_ioctl = dgrp_dpa_ioctl,
+ .open = dgrp_dpa_open,
+ .release = dgrp_dpa_release,
+};
+
+static struct inode_operations dpa_inode_ops = {
+ .permission = dgrp_inode_permission
+};
+
+
+
+struct digi_node {
+ uint nd_state; /* Node state: 1 = up, 0 = down. */
+ uint nd_chan_count; /* Number of channels found */
+ uint nd_tx_byte; /* Tx data count */
+ uint nd_rx_byte; /* RX data count */
+ u8 nd_ps_desc[MAX_DESC_LEN]; /* Description from PS */
+};
+
+#define DIGI_GETNODE (('d'<<8) | 249) /* get board info */
+
+
+struct digi_chan {
+ uint ch_port; /* Port number to get info on */
+ uint ch_open; /* 1 if open, 0 if not */
+ uint ch_txcount; /* TX data count */
+ uint ch_rxcount; /* RX data count */
+ uint ch_s_brate; /* Realport BRATE */
+ uint ch_s_estat; /* Realport ELAST */
+ uint ch_s_cflag; /* Realport CFLAG */
+ uint ch_s_iflag; /* Realport IFLAG */
+ uint ch_s_oflag; /* Realport OFLAG */
+ uint ch_s_xflag; /* Realport XFLAG */
+ uint ch_s_mstat; /* Realport MLAST */
+};
+
+#define DIGI_GETCHAN (('d'<<8) | 248) /* get channel info */
+
+
+struct digi_vpd {
+ int vpd_len;
+ char vpd_data[VPDSIZE];
+};
+
+#define DIGI_GETVPD (('d'<<8) | 246) /* get VPD info */
+
+
+struct digi_debug {
+ int onoff;
+ int port;
+};
+
+#define DIGI_SETDEBUG (('d'<<8) | 247) /* set debug info */
+
+
+void dgrp_register_dpa_hook(struct proc_dir_entry *de)
+{
+ struct nd_struct *node = de->data;
+
+ de->proc_iops = &dpa_inode_ops;
+ de->proc_fops = &dpa_ops;
+
+ node->nd_dpa_de = de;
+ spin_lock_init(&node->nd_dpa_lock);
+}
+
+/*
+ * dgrp_dpa_open -- open the DPA device for a particular PortServer
+ */
+static int dgrp_dpa_open(struct inode *inode, struct file *file)
+{
+ struct nd_struct *nd;
+ int rtn = 0;
+
+ struct proc_dir_entry *de;
+
+ rtn = try_module_get(THIS_MODULE);
+ if (!rtn)
+ return -ENXIO;
+
+ rtn = 0;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ rtn = -EPERM;
+ goto done;
+ }
+
+ /*
+ * Make sure that the "private_data" field hasn't already been used.
+ */
+ if (file->private_data) {
+ rtn = -EINVAL;
+ goto done;
+ }
+
+ /*
+ * Get the node pointer, and fail if it doesn't exist.
+ */
+ de = PDE(inode);
+ if (!de) {
+ rtn = -ENXIO;
+ goto done;
+ }
+ nd = (struct nd_struct *)de->data;
+ if (!nd) {
+ rtn = -ENXIO;
+ goto done;
+ }
+
+ file->private_data = (void *) nd;
+
+ /*
+ * Allocate the DPA buffer.
+ */
+
+ if (nd->nd_dpa_buf) {
+ rtn = -EBUSY;
+ } else {
+ nd->nd_dpa_buf = kmalloc(DPA_MAX, GFP_KERNEL);
+
+ if (!nd->nd_dpa_buf) {
+ rtn = -ENOMEM;
+ } else {
+ nd->nd_dpa_out = 0;
+ nd->nd_dpa_in = 0;
+ nd->nd_dpa_lbolt = jiffies;
+ }
+ }
+
+done:
+
+ if (rtn)
+ module_put(THIS_MODULE);
+ return rtn;
+}
+
+/*
+ * dgrp_dpa_release -- close the DPA device for a particular PortServer
+ */
+static int dgrp_dpa_release(struct inode *inode, struct file *file)
+{
+ struct nd_struct *nd;
+ u8 *buf;
+ unsigned long lock_flags;
+
+ /*
+ * Get the node pointer, and quit if it doesn't exist.
+ */
+ nd = (struct nd_struct *)(file->private_data);
+ if (!nd)
+ goto done;
+
+ /*
+ * Free the dpa buffer.
+ */
+
+ spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
+
+ buf = nd->nd_dpa_buf;
+
+ nd->nd_dpa_buf = NULL;
+ nd->nd_dpa_out = nd->nd_dpa_in;
+
+ /*
+ * Wakeup any thread waiting for buffer space.
+ */
+
+ if (nd->nd_dpa_flag & DPA_WAIT_SPACE) {
+ nd->nd_dpa_flag &= ~DPA_WAIT_SPACE;
+ wake_up_interruptible(&nd->nd_dpa_wqueue);
+ }
+
+ spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
+
+ kfree(buf);
+
+done:
+ module_put(THIS_MODULE);
+ file->private_data = NULL;
+ return 0;
+}
+
+/*
+ * dgrp_dpa_read
+ *
+ * Copy data from the monitoring buffer to the user, freeing space
+ * in the monitoring buffer for more messages
+ */
+static ssize_t dgrp_dpa_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct nd_struct *nd;
+ int n;
+ int r;
+ int offset = 0;
+ int res = 0;
+ ssize_t rtn;
+ unsigned long lock_flags;
+
+ /*
+ * Get the node pointer, and quit if it doesn't exist.
+ */
+ nd = (struct nd_struct *)(file->private_data);
+ if (!nd)
+ return -ENXIO;
+
+ /*
+ * Wait for some data to appear in the buffer.
+ */
+
+ spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
+
+ for (;;) {
+ n = (nd->nd_dpa_in - nd->nd_dpa_out) & DPA_MASK;
+
+ if (n != 0)
+ break;
+
+ nd->nd_dpa_flag |= DPA_WAIT_DATA;
+
+ spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
+
+ /*
+ * Go to sleep waiting until the condition becomes true.
+ */
+ rtn = wait_event_interruptible(nd->nd_dpa_wqueue,
+ ((nd->nd_dpa_flag & DPA_WAIT_DATA) == 0));
+
+ if (rtn)
+ return rtn;
+
+ spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
+ }
+
+ /*
+ * Read whatever is there.
+ */
+
+ if (n > count)
+ n = count;
+
+ res = n;
+
+ r = DPA_MAX - nd->nd_dpa_out;
+
+ if (r <= n) {
+
+ spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
+ rtn = copy_to_user((void __user *)buf,
+ nd->nd_dpa_buf + nd->nd_dpa_out, r);
+ spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
+
+ if (rtn) {
+ rtn = -EFAULT;
+ goto done;
+ }
+
+ nd->nd_dpa_out = 0;
+ n -= r;
+ offset = r;
+ }
+
+ spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
+ rtn = copy_to_user((void __user *)buf + offset,
+ nd->nd_dpa_buf + nd->nd_dpa_out, n);
+ spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
+
+ if (rtn) {
+ rtn = -EFAULT;
+ goto done;
+ }
+
+ nd->nd_dpa_out += n;
+
+ *ppos += res;
+
+ rtn = res;
+
+ /*
+ * Wakeup any thread waiting for buffer space.
+ */
+
+ n = (nd->nd_dpa_in - nd->nd_dpa_out) & DPA_MASK;
+
+ if (nd->nd_dpa_flag & DPA_WAIT_SPACE &&
+ (DPA_MAX - n) > DPA_HIGH_WATER) {
+ nd->nd_dpa_flag &= ~DPA_WAIT_SPACE;
+ wake_up_interruptible(&nd->nd_dpa_wqueue);
+ }
+
+ done:
+ spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
+ return rtn;
+}
+
+static unsigned int dgrp_dpa_select(struct file *file,
+ struct poll_table_struct *table)
+{
+ unsigned int retval = 0;
+ struct nd_struct *nd = file->private_data;
+
+ if (nd->nd_dpa_out != nd->nd_dpa_in)
+ retval |= POLLIN | POLLRDNORM; /* Conditionally readable */
+
+ retval |= POLLOUT | POLLWRNORM; /* Always writeable */
+
+ return retval;
+}
+
+static long dgrp_dpa_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+
+ struct nd_struct *nd;
+ struct digi_chan getchan;
+ struct digi_node getnode;
+ struct ch_struct *ch;
+ struct digi_debug setdebug;
+ struct digi_vpd vpd;
+ unsigned int port;
+ void __user *uarg = (void __user *) arg;
+
+ nd = file->private_data;
+
+ switch (cmd) {
+ case DIGI_GETCHAN:
+ if (copy_from_user(&getchan, uarg, sizeof(struct digi_chan)))
+ return -EFAULT;
+
+ port = getchan.ch_port;
+
+ if (port < 0 || port > nd->nd_chan_count)
+ return -EINVAL;
+
+ ch = nd->nd_chan + port;
+
+ getchan.ch_open = (ch->ch_open_count > 0) ? 1 : 0;
+ getchan.ch_txcount = ch->ch_txcount;
+ getchan.ch_rxcount = ch->ch_rxcount;
+ getchan.ch_s_brate = ch->ch_s_brate;
+ getchan.ch_s_estat = ch->ch_s_elast;
+ getchan.ch_s_cflag = ch->ch_s_cflag;
+ getchan.ch_s_iflag = ch->ch_s_iflag;
+ getchan.ch_s_oflag = ch->ch_s_oflag;
+ getchan.ch_s_xflag = ch->ch_s_xflag;
+ getchan.ch_s_mstat = ch->ch_s_mlast;
+
+ if (copy_to_user(uarg, &getchan, sizeof(struct digi_chan)))
+ return -EFAULT;
+ break;
+
+
+ case DIGI_GETNODE:
+ getnode.nd_state = (nd->nd_state & NS_READY) ? 1 : 0;
+ getnode.nd_chan_count = nd->nd_chan_count;
+ getnode.nd_tx_byte = nd->nd_tx_byte;
+ getnode.nd_rx_byte = nd->nd_rx_byte;
+
+ memset(&getnode.nd_ps_desc, 0, MAX_DESC_LEN);
+ strncpy(getnode.nd_ps_desc, nd->nd_ps_desc, MAX_DESC_LEN);
+
+ if (copy_to_user(uarg, &getnode, sizeof(struct digi_node)))
+ return -EFAULT;
+ break;
+
+
+ case DIGI_SETDEBUG:
+ if (copy_from_user(&setdebug, uarg, sizeof(struct digi_debug)))
+ return -EFAULT;
+
+ nd->nd_dpa_debug = setdebug.onoff;
+ nd->nd_dpa_port = setdebug.port;
+ break;
+
+
+ case DIGI_GETVPD:
+ if (nd->nd_vpd_len > 0) {
+ vpd.vpd_len = nd->nd_vpd_len;
+ memcpy(&vpd.vpd_data, &nd->nd_vpd, nd->nd_vpd_len);
+ } else {
+ vpd.vpd_len = 0;
+ }
+
+ if (copy_to_user(uarg, &vpd, sizeof(struct digi_vpd)))
+ return -EFAULT;
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * dgrp_dpa() -- send data to the device monitor queue
+ * @nd: pointer to a node structure
+ * @buf: buffer of data to copy to the monitoring buffer
+ * @len: number of bytes to transfer to the buffer
+ *
+ * Called by the net device routines to send data to the device
+ * monitor queue. If the device monitor buffer is too full to
+ * accept the data, it waits until the buffer is ready.
+ */
+static void dgrp_dpa(struct nd_struct *nd, u8 *buf, int nbuf)
+{
+ int n;
+ int r;
+ unsigned long lock_flags;
+
+ /*
+ * Grab DPA lock.
+ */
+ spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
+
+ /*
+ * Loop while data remains.
+ */
+ while (nbuf > 0 && nd->nd_dpa_buf != NULL) {
+
+ n = (nd->nd_dpa_out - nd->nd_dpa_in - 1) & DPA_MASK;
+
+ /*
+ * Enforce flow control on the DPA device.
+ */
+ if (n < (DPA_MAX - DPA_HIGH_WATER))
+ nd->nd_dpa_flag |= DPA_WAIT_SPACE;
+
+ /*
+ * This should never happen, as the flow control above
+ * should have stopped things before they got to this point.
+ */
+ if (n == 0) {
+ spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
+ return;
+ }
+
+ /*
+ * Copy as much data as will fit.
+ */
+
+ if (n > nbuf)
+ n = nbuf;
+
+ r = DPA_MAX - nd->nd_dpa_in;
+
+ if (r <= n) {
+ memcpy(nd->nd_dpa_buf + nd->nd_dpa_in, buf, r);
+
+ n -= r;
+
+ nd->nd_dpa_in = 0;
+
+ buf += r;
+ nbuf -= r;
+ }
+
+ memcpy(nd->nd_dpa_buf + nd->nd_dpa_in, buf, n);
+
+ nd->nd_dpa_in += n;
+
+ buf += n;
+ nbuf -= n;
+
+ if (nd->nd_dpa_in >= DPA_MAX)
+ pr_info_ratelimited("%s - nd->nd_dpa_in (%i) >= DPA_MAX\n",
+ __func__, nd->nd_dpa_in);
+
+ /*
+ * Wakeup any thread waiting for data
+ */
+ if (nd->nd_dpa_flag & DPA_WAIT_DATA) {
+ nd->nd_dpa_flag &= ~DPA_WAIT_DATA;
+ wake_up_interruptible(&nd->nd_dpa_wqueue);
+ }
+ }
+
+ /*
+ * Release the DPA lock.
+ */
+ spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
+}
+
+/**
+ * dgrp_monitor_data() -- builds a DPA data packet
+ * @nd: pointer to a node structure
+ * @type: type of message to be logged in the DPA buffer
+ * @buf: buffer of data to be logged in the DPA buffer
+ * @size -- number of bytes in the "buf" buffer
+ */
+void dgrp_dpa_data(struct nd_struct *nd, int type, u8 *buf, int size)
+{
+ u8 header[5];
+
+ header[0] = type;
+
+ put_unaligned_be32(size, header + 1);
+
+ dgrp_dpa(nd, header, sizeof(header));
+ dgrp_dpa(nd, buf, size);
+}
diff --git a/drivers/staging/dgrp/dgrp_driver.c b/drivers/staging/dgrp/dgrp_driver.c
new file mode 100644
index 000000000000..6e4a0ebc0749
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_driver.c
@@ -0,0 +1,110 @@
+/*
+ *
+ * Copyright 1999-2003 Digi International (www.digi.com)
+ * Jeff Randall
+ * James Puzzo <jamesp at digi dot com>
+ * Scott Kilau <Scott_Kilau at digi dot com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ */
+
+/*
+ * Driver specific includes
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+
+/*
+ * PortServer includes
+ */
+#include "dgrp_common.h"
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Digi International, http://www.digi.com");
+MODULE_DESCRIPTION("RealPort driver for Digi's ethernet-based serial connectivity product line");
+MODULE_VERSION(DIGI_VERSION);
+
+struct list_head nd_struct_list;
+struct dgrp_poll_data dgrp_poll_data;
+
+int dgrp_rawreadok = 1; /* Bypass flipbuf on input */
+int dgrp_register_cudevices = 1;/* Turn on/off registering legacy cu devices */
+int dgrp_register_prdevices = 1;/* Turn on/off registering transparent print */
+int dgrp_poll_tick = 20; /* Poll interval - in ms */
+
+module_param_named(rawreadok, dgrp_rawreadok, int, 0644);
+MODULE_PARM_DESC(rawreadok, "Bypass flip buffers on input");
+
+module_param_named(register_cudevices, dgrp_register_cudevices, int, 0644);
+MODULE_PARM_DESC(register_cudevices, "Turn on/off registering legacy cu devices");
+
+module_param_named(register_prdevices, dgrp_register_prdevices, int, 0644);
+MODULE_PARM_DESC(register_prdevices, "Turn on/off registering transparent print devices");
+
+module_param_named(pollrate, dgrp_poll_tick, int, 0644);
+MODULE_PARM_DESC(pollrate, "Poll interval in ms");
+
+/* Driver load/unload functions */
+static int dgrp_init_module(void);
+static void dgrp_cleanup_module(void);
+
+module_init(dgrp_init_module);
+module_exit(dgrp_cleanup_module);
+
+/*
+ * init_module()
+ *
+ * Module load. This is where it all starts.
+ */
+static int dgrp_init_module(void)
+{
+ INIT_LIST_HEAD(&nd_struct_list);
+
+ spin_lock_init(&dgrp_poll_data.poll_lock);
+ init_timer(&dgrp_poll_data.timer);
+ dgrp_poll_data.poll_tick = dgrp_poll_tick;
+ dgrp_poll_data.timer.function = dgrp_poll_handler;
+ dgrp_poll_data.timer.data = (unsigned long) &dgrp_poll_data;
+
+ dgrp_create_class_sysfs_files();
+
+ dgrp_register_proc();
+
+ return 0;
+}
+
+
+/*
+ * Module unload. This is where it all ends.
+ */
+static void dgrp_cleanup_module(void)
+{
+ struct nd_struct *nd, *next;
+
+ /*
+ * Attempting to free resources in backwards
+ * order of allocation, in case that helps
+ * memory pool fragmentation.
+ */
+ dgrp_unregister_proc();
+
+ dgrp_remove_class_sysfs_files();
+
+
+ list_for_each_entry_safe(nd, next, &nd_struct_list, list) {
+ dgrp_tty_uninit(nd);
+ kfree(nd);
+ }
+}
diff --git a/drivers/staging/dgrp/dgrp_mon_ops.c b/drivers/staging/dgrp/dgrp_mon_ops.c
new file mode 100644
index 000000000000..268dcb95204b
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_mon_ops.c
@@ -0,0 +1,346 @@
+/*****************************************************************************
+ *
+ * Copyright 1999 Digi International (www.digi.com)
+ * James Puzzo <jamesp at digi dot com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ */
+
+/*
+ *
+ * Filename:
+ *
+ * dgrp_mon_ops.c
+ *
+ * Description:
+ *
+ * Handle the file operations required for the "monitor" devices.
+ * Includes those functions required to register the "mon" devices
+ * in "/proc".
+ *
+ * Author:
+ *
+ * James A. Puzzo
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <asm/unaligned.h>
+#include <linux/proc_fs.h>
+
+#include "dgrp_common.h"
+
+/* File operation declarations */
+static int dgrp_mon_open(struct inode *, struct file *);
+static int dgrp_mon_release(struct inode *, struct file *);
+static ssize_t dgrp_mon_read(struct file *, char __user *, size_t, loff_t *);
+static long dgrp_mon_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg);
+
+static const struct file_operations mon_ops = {
+ .owner = THIS_MODULE,
+ .read = dgrp_mon_read,
+ .unlocked_ioctl = dgrp_mon_ioctl,
+ .open = dgrp_mon_open,
+ .release = dgrp_mon_release,
+};
+
+static struct inode_operations mon_inode_ops = {
+ .permission = dgrp_inode_permission
+};
+
+void dgrp_register_mon_hook(struct proc_dir_entry *de)
+{
+ struct nd_struct *node = de->data;
+
+ de->proc_iops = &mon_inode_ops;
+ de->proc_fops = &mon_ops;
+ node->nd_mon_de = de;
+ sema_init(&node->nd_mon_semaphore, 1);
+}
+
+/**
+ * dgrp_mon_open() -- open /proc/dgrp/ports device for a PortServer
+ * @inode: struct inode *
+ * @file: struct file *
+ *
+ * Open function to open the /proc/dgrp/ports device for a PortServer.
+ */
+static int dgrp_mon_open(struct inode *inode, struct file *file)
+{
+ struct nd_struct *nd;
+ struct proc_dir_entry *de;
+ struct timeval tv;
+ uint32_t time;
+ u8 *buf;
+ int rtn;
+
+ rtn = try_module_get(THIS_MODULE);
+ if (!rtn)
+ return -ENXIO;
+
+ rtn = 0;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ rtn = -EPERM;
+ goto done;
+ }
+
+ /*
+ * Make sure that the "private_data" field hasn't already been used.
+ */
+ if (file->private_data) {
+ rtn = -EINVAL;
+ goto done;
+ }
+
+ /*
+ * Get the node pointer, and fail if it doesn't exist.
+ */
+ de = PDE(inode);
+ if (!de) {
+ rtn = -ENXIO;
+ goto done;
+ }
+
+ nd = (struct nd_struct *)de->data;
+ if (!nd) {
+ rtn = -ENXIO;
+ goto done;
+ }
+
+ file->private_data = (void *) nd;
+
+ /*
+ * Allocate the monitor buffer.
+ */
+
+ /*
+ * Grab the MON lock.
+ */
+ down(&nd->nd_mon_semaphore);
+
+ if (nd->nd_mon_buf) {
+ rtn = -EBUSY;
+ goto done_up;
+ }
+
+ nd->nd_mon_buf = kmalloc(MON_MAX, GFP_KERNEL);
+
+ if (!nd->nd_mon_buf) {
+ rtn = -ENOMEM;
+ goto done_up;
+ }
+
+ /*
+ * Enter an RPDUMP file header into the buffer.
+ */
+
+ buf = nd->nd_mon_buf;
+
+ strcpy(buf, RPDUMP_MAGIC);
+ buf += strlen(buf) + 1;
+
+ do_gettimeofday(&tv);
+
+ /*
+ * tv.tv_sec might be a 64 bit quantity. Pare
+ * it down to 32 bits before attempting to encode
+ * it.
+ */
+ time = (uint32_t) (tv.tv_sec & 0xffffffff);
+
+ put_unaligned_be32(time, buf);
+ put_unaligned_be16(0, buf + 4);
+ buf += 6;
+
+ if (nd->nd_tx_module) {
+ buf[0] = RPDUMP_CLIENT;
+ put_unaligned_be32(0, buf + 1);
+ put_unaligned_be16(1, buf + 5);
+ buf[7] = 0xf0 + nd->nd_tx_module;
+ buf += 8;
+ }
+
+ if (nd->nd_rx_module) {
+ buf[0] = RPDUMP_SERVER;
+ put_unaligned_be32(0, buf + 1);
+ put_unaligned_be16(1, buf + 5);
+ buf[7] = 0xf0 + nd->nd_rx_module;
+ buf += 8;
+ }
+
+ nd->nd_mon_out = 0;
+ nd->nd_mon_in = buf - nd->nd_mon_buf;
+ nd->nd_mon_lbolt = jiffies;
+
+done_up:
+ up(&nd->nd_mon_semaphore);
+
+done:
+ if (rtn)
+ module_put(THIS_MODULE);
+ return rtn;
+}
+
+
+/**
+ * dgrp_mon_release() - Close the MON device for a particular PortServer
+ * @inode: struct inode *
+ * @file: struct file *
+ */
+static int dgrp_mon_release(struct inode *inode, struct file *file)
+{
+ struct nd_struct *nd;
+
+ /*
+ * Get the node pointer, and quit if it doesn't exist.
+ */
+ nd = (struct nd_struct *)(file->private_data);
+ if (!nd)
+ goto done;
+
+ /*
+ * Free the monitor buffer.
+ */
+
+ down(&nd->nd_mon_semaphore);
+
+ kfree(nd->nd_mon_buf);
+ nd->nd_mon_buf = NULL;
+ nd->nd_mon_out = nd->nd_mon_in;
+
+ /*
+ * Wakeup any thread waiting for buffer space.
+ */
+
+ if (nd->nd_mon_flag & MON_WAIT_SPACE) {
+ nd->nd_mon_flag &= ~MON_WAIT_SPACE;
+ wake_up_interruptible(&nd->nd_mon_wqueue);
+ }
+
+ up(&nd->nd_mon_semaphore);
+
+ /*
+ * Make sure there is no thread in the middle of writing a packet.
+ */
+ down(&nd->nd_net_semaphore);
+ up(&nd->nd_net_semaphore);
+
+done:
+ module_put(THIS_MODULE);
+ file->private_data = NULL;
+ return 0;
+}
+
+/**
+ * dgrp_mon_read() -- Copy data from the monitoring buffer to the user
+ */
+static ssize_t dgrp_mon_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct nd_struct *nd;
+ int r;
+ int offset = 0;
+ int res = 0;
+ ssize_t rtn;
+
+ /*
+ * Get the node pointer, and quit if it doesn't exist.
+ */
+ nd = (struct nd_struct *)(file->private_data);
+ if (!nd)
+ return -ENXIO;
+
+ /*
+ * Wait for some data to appear in the buffer.
+ */
+
+ down(&nd->nd_mon_semaphore);
+
+ for (;;) {
+ res = (nd->nd_mon_in - nd->nd_mon_out) & MON_MASK;
+
+ if (res)
+ break;
+
+ nd->nd_mon_flag |= MON_WAIT_DATA;
+
+ up(&nd->nd_mon_semaphore);
+
+ /*
+ * Go to sleep waiting until the condition becomes true.
+ */
+ rtn = wait_event_interruptible(nd->nd_mon_wqueue,
+ ((nd->nd_mon_flag & MON_WAIT_DATA) == 0));
+
+ if (rtn)
+ return rtn;
+
+ down(&nd->nd_mon_semaphore);
+ }
+
+ /*
+ * Read whatever is there.
+ */
+
+ if (res > count)
+ res = count;
+
+ r = MON_MAX - nd->nd_mon_out;
+
+ if (r <= res) {
+ rtn = copy_to_user((void __user *)buf,
+ nd->nd_mon_buf + nd->nd_mon_out, r);
+ if (rtn) {
+ up(&nd->nd_mon_semaphore);
+ return -EFAULT;
+ }
+
+ nd->nd_mon_out = 0;
+ res -= r;
+ offset = r;
+ }
+
+ rtn = copy_to_user((void __user *) buf + offset,
+ nd->nd_mon_buf + nd->nd_mon_out, res);
+ if (rtn) {
+ up(&nd->nd_mon_semaphore);
+ return -EFAULT;
+ }
+
+ nd->nd_mon_out += res;
+
+ *ppos += res;
+
+ up(&nd->nd_mon_semaphore);
+
+ /*
+ * Wakeup any thread waiting for buffer space.
+ */
+
+ if (nd->nd_mon_flag & MON_WAIT_SPACE) {
+ nd->nd_mon_flag &= ~MON_WAIT_SPACE;
+ wake_up_interruptible(&nd->nd_mon_wqueue);
+ }
+
+ return res;
+}
+
+/* ioctl is not valid on monitor device */
+static long dgrp_mon_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return -EINVAL;
+}
diff --git a/drivers/staging/dgrp/dgrp_net_ops.c b/drivers/staging/dgrp/dgrp_net_ops.c
new file mode 100644
index 000000000000..ab839ea3b44c
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_net_ops.c
@@ -0,0 +1,3737 @@
+/*
+ *
+ * Copyright 1999 Digi International (www.digi.com)
+ * James Puzzo <jamesp at digi dot com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ */
+
+/*
+ *
+ * Filename:
+ *
+ * dgrp_net_ops.c
+ *
+ * Description:
+ *
+ * Handle the file operations required for the "network" devices.
+ * Includes those functions required to register the "net" devices
+ * in "/proc".
+ *
+ * Author:
+ *
+ * James A. Puzzo
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/spinlock.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/ratelimit.h>
+#include <asm/unaligned.h>
+
+#define MYFLIPLEN TBUF_MAX
+
+#include "dgrp_common.h"
+
+#define TTY_FLIPBUF_SIZE 512
+#define DEVICE_NAME_SIZE 50
+
+/*
+ * Generic helper function declarations
+ */
+static void parity_scan(struct ch_struct *ch, unsigned char *cbuf,
+ unsigned char *fbuf, int *len);
+
+/*
+ * File operation declarations
+ */
+static int dgrp_net_open(struct inode *, struct file *);
+static int dgrp_net_release(struct inode *, struct file *);
+static ssize_t dgrp_net_read(struct file *, char __user *, size_t, loff_t *);
+static ssize_t dgrp_net_write(struct file *, const char __user *, size_t,
+ loff_t *);
+static long dgrp_net_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg);
+static unsigned int dgrp_net_select(struct file *file,
+ struct poll_table_struct *table);
+
+static const struct file_operations net_ops = {
+ .owner = THIS_MODULE,
+ .read = dgrp_net_read,
+ .write = dgrp_net_write,
+ .poll = dgrp_net_select,
+ .unlocked_ioctl = dgrp_net_ioctl,
+ .open = dgrp_net_open,
+ .release = dgrp_net_release,
+};
+
+static struct inode_operations net_inode_ops = {
+ .permission = dgrp_inode_permission
+};
+
+void dgrp_register_net_hook(struct proc_dir_entry *de)
+{
+ struct nd_struct *node = de->data;
+
+ de->proc_iops = &net_inode_ops;
+ de->proc_fops = &net_ops;
+ node->nd_net_de = de;
+ sema_init(&node->nd_net_semaphore, 1);
+ node->nd_state = NS_CLOSED;
+ dgrp_create_node_class_sysfs_files(node);
+}
+
+
+/**
+ * dgrp_dump() -- prints memory for debugging purposes.
+ * @mem: Memory location which should be printed to the console
+ * @len: Number of bytes to be dumped
+ */
+static void dgrp_dump(u8 *mem, int len)
+{
+ int i;
+
+ pr_debug("dgrp dump length = %d, data = ", len);
+ for (i = 0; i < len; ++i)
+ pr_debug("%.2x ", mem[i]);
+ pr_debug("\n");
+}
+
+/**
+ * dgrp_read_data_block() -- Read a data block
+ * @ch: struct ch_struct *
+ * @flipbuf: u8 *
+ * @flipbuf_size: size of flipbuf
+ */
+static void dgrp_read_data_block(struct ch_struct *ch, u8 *flipbuf,
+ int flipbuf_size)
+{
+ int t;
+ int n;
+
+ if (flipbuf_size <= 0)
+ return;
+
+ t = RBUF_MAX - ch->ch_rout;
+ n = flipbuf_size;
+
+ if (n >= t) {
+ memcpy(flipbuf, ch->ch_rbuf + ch->ch_rout, t);
+ flipbuf += t;
+ n -= t;
+ ch->ch_rout = 0;
+ }
+
+ memcpy(flipbuf, ch->ch_rbuf + ch->ch_rout, n);
+ flipbuf += n;
+ ch->ch_rout += n;
+}
+
+
+/**
+ * dgrp_input() -- send data to the line disipline
+ * @ch: pointer to channel struct
+ *
+ * Copys the rbuf to the flipbuf and sends to line discipline.
+ * Sends input buffer data to the line discipline.
+ *
+ * There are several modes to consider here:
+ * rawreadok, tty->real_raw, and IF_PARMRK
+ */
+static void dgrp_input(struct ch_struct *ch)
+{
+ struct nd_struct *nd;
+ struct tty_struct *tty;
+ int remain;
+ int data_len;
+ int len;
+ int flip_len;
+ int tty_count;
+ ulong lock_flags;
+ struct tty_ldisc *ld;
+ u8 *myflipbuf;
+ u8 *myflipflagbuf;
+
+ if (!ch)
+ return;
+
+ nd = ch->ch_nd;
+
+ if (!nd)
+ return;
+
+ spin_lock_irqsave(&nd->nd_lock, lock_flags);
+
+ myflipbuf = nd->nd_inputbuf;
+ myflipflagbuf = nd->nd_inputflagbuf;
+
+ if (!ch->ch_open_count) {
+ ch->ch_rout = ch->ch_rin;
+ goto out;
+ }
+
+ if (ch->ch_tun.un_flag & UN_CLOSING) {
+ ch->ch_rout = ch->ch_rin;
+ goto out;
+ }
+
+ tty = (ch->ch_tun).un_tty;
+
+
+ if (!tty || tty->magic != TTY_MAGIC) {
+ ch->ch_rout = ch->ch_rin;
+ goto out;
+ }
+
+ tty_count = tty->count;
+ if (!tty_count) {
+ ch->ch_rout = ch->ch_rin;
+ goto out;
+ }
+
+ if (tty->closing || test_bit(TTY_CLOSING, &tty->flags)) {
+ ch->ch_rout = ch->ch_rin;
+ goto out;
+ }
+
+ spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
+
+ /* Decide how much data we can send into the tty layer */
+ if (dgrp_rawreadok && tty->real_raw)
+ flip_len = MYFLIPLEN;
+ else
+ flip_len = TTY_FLIPBUF_SIZE;
+
+ /* data_len should be the number of chars that we read in */
+ data_len = (ch->ch_rin - ch->ch_rout) & RBUF_MASK;
+ remain = data_len;
+
+ /* len is the amount of data we are going to transfer here */
+ len = min(data_len, flip_len);
+
+ /* take into consideration length of ldisc */
+ len = min(len, (N_TTY_BUF_SIZE - 1) - tty->read_cnt);
+
+ ld = tty_ldisc_ref(tty);
+
+ /*
+ * If we were unable to get a reference to the ld,
+ * don't flush our buffer, and act like the ld doesn't
+ * have any space to put the data right now.
+ */
+ if (!ld) {
+ len = 0;
+ } else if (!ld->ops->receive_buf) {
+ spin_lock_irqsave(&nd->nd_lock, lock_flags);
+ ch->ch_rout = ch->ch_rin;
+ spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
+ len = 0;
+ }
+
+ /* Check DPA flow control */
+ if ((nd->nd_dpa_debug) &&
+ (nd->nd_dpa_flag & DPA_WAIT_SPACE) &&
+ (nd->nd_dpa_port == MINOR(tty_devnum(ch->ch_tun.un_tty))))
+ len = 0;
+
+ if ((len) && !(ch->ch_flag & CH_RXSTOP)) {
+
+ dgrp_read_data_block(ch, myflipbuf, len);
+
+ /*
+ * In high performance mode, we don't have to update
+ * flag_buf or any of the counts or pointers into flip buf.
+ */
+ if (!dgrp_rawreadok || !tty->real_raw) {
+ if (I_PARMRK(tty) || I_BRKINT(tty) || I_INPCK(tty))
+ parity_scan(ch, myflipbuf, myflipflagbuf, &len);
+ else
+ memset(myflipflagbuf, TTY_NORMAL, len);
+ }
+
+ if ((nd->nd_dpa_debug) &&
+ (nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(tty)))))
+ dgrp_dpa_data(nd, 1, myflipbuf, len);
+
+ /*
+ * If we're doing raw reads, jam it right into the
+ * line disc bypassing the flip buffers.
+ */
+ if (dgrp_rawreadok && tty->real_raw)
+ ld->ops->receive_buf(tty, myflipbuf, NULL, len);
+ else {
+ len = tty_buffer_request_room(tty, len);
+ tty_insert_flip_string_flags(tty, myflipbuf,
+ myflipflagbuf, len);
+
+ /* Tell the tty layer its okay to "eat" the data now */
+ tty_flip_buffer_push(tty);
+ }
+
+ ch->ch_rxcount += len;
+ }
+
+ if (ld)
+ tty_ldisc_deref(ld);
+
+ /*
+ * Wake up any sleepers (maybe dgrp close) that might be waiting
+ * for a channel flag state change.
+ */
+ wake_up_interruptible(&ch->ch_flag_wait);
+ return;
+
+out:
+ spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
+}
+
+
+/*
+ * parity_scan
+ *
+ * Loop to inspect each single character or 0xFF escape.
+ *
+ * if PARMRK & ~DOSMODE:
+ * 0xFF 0xFF Normal 0xFF character, escaped
+ * to eliminate confusion.
+ * 0xFF 0x00 0x00 Break
+ * 0xFF 0x00 CC Error character CC.
+ * CC Normal character CC.
+ *
+ * if PARMRK & DOSMODE:
+ * 0xFF 0x18 0x00 Break
+ * 0xFF 0x08 0x00 Framing Error
+ * 0xFF 0x04 0x00 Parity error
+ * 0xFF 0x0C 0x00 Both Framing and Parity error
+ *
+ * TODO: do we need to do the XMODEM, XOFF, XON, XANY processing??
+ * as per protocol
+ */
+static void parity_scan(struct ch_struct *ch, unsigned char *cbuf,
+ unsigned char *fbuf, int *len)
+{
+ int l = *len;
+ int count = 0;
+ int DOS = ((ch->ch_iflag & IF_DOSMODE) == 0 ? 0 : 1);
+ unsigned char *cout; /* character buffer */
+ unsigned char *fout; /* flag buffer */
+ unsigned char *in;
+ unsigned char c;
+
+ in = cbuf;
+ cout = cbuf;
+ fout = fbuf;
+
+ while (l--) {
+ c = *in;
+ in++;
+
+ switch (ch->ch_pscan_state) {
+ default:
+ /* reset to sanity and fall through */
+ ch->ch_pscan_state = 0 ;
+
+ case 0:
+ /* No FF seen yet */
+ if (c == 0xff) /* delete this character from stream */
+ ch->ch_pscan_state = 1;
+ else {
+ *cout++ = c;
+ *fout++ = TTY_NORMAL;
+ count += 1;
+ }
+ break;
+
+ case 1:
+ /* first FF seen */
+ if (c == 0xff) {
+ /* doubled ff, transform to single ff */
+ *cout++ = c;
+ *fout++ = TTY_NORMAL;
+ count += 1;
+ ch->ch_pscan_state = 0;
+ } else {
+ /* save value examination in next state */
+ ch->ch_pscan_savechar = c;
+ ch->ch_pscan_state = 2;
+ }
+ break;
+
+ case 2:
+ /* third character of ff sequence */
+ *cout++ = c;
+ if (DOS) {
+ if (ch->ch_pscan_savechar & 0x10)
+ *fout++ = TTY_BREAK;
+ else if (ch->ch_pscan_savechar & 0x08)
+ *fout++ = TTY_FRAME;
+ else
+ /*
+ * either marked as a parity error,
+ * indeterminate, or not in DOSMODE
+ * call it a parity error
+ */
+ *fout++ = TTY_PARITY;
+ } else {
+ /* case FF XX ?? where XX is not 00 */
+ if (ch->ch_pscan_savechar & 0xff) {
+ /* this should not happen */
+ pr_info("%s: parity_scan: error unexpected byte\n",
+ __func__);
+ *fout++ = TTY_PARITY;
+ }
+ /* case FF 00 XX where XX is not 00 */
+ else if (c == 0xff)
+ *fout++ = TTY_PARITY;
+ /* case FF 00 00 */
+ else
+ *fout++ = TTY_BREAK;
+
+ }
+ count += 1;
+ ch->ch_pscan_state = 0;
+ }
+ }
+ *len = count;
+}
+
+
+/**
+ * dgrp_net_idle() -- Idle the network connection
+ * @nd: pointer to node structure to idle
+ */
+static void dgrp_net_idle(struct nd_struct *nd)
+{
+ struct ch_struct *ch;
+ int i;
+
+ nd->nd_tx_work = 1;
+
+ nd->nd_state = NS_IDLE;
+ nd->nd_flag = 0;
+
+ for (i = nd->nd_seq_out; ; i = (i + 1) & SEQ_MASK) {
+ if (!nd->nd_seq_wait[i]) {
+ nd->nd_seq_wait[i] = 0;
+ wake_up_interruptible(&nd->nd_seq_wque[i]);
+ }
+
+ if (i == nd->nd_seq_in)
+ break;
+ }
+
+ nd->nd_seq_out = nd->nd_seq_in;
+
+ nd->nd_unack = 0;
+ nd->nd_remain = 0;
+
+ nd->nd_tx_module = 0x10;
+ nd->nd_rx_module = 0x00;
+
+ for (i = 0, ch = nd->nd_chan; i < CHAN_MAX; i++, ch++) {
+ ch->ch_state = CS_IDLE;
+
+ ch->ch_otype = 0;
+ ch->ch_otype_waiting = 0;
+ }
+}
+
+/*
+ * Increase the number of channels, waking up any
+ * threads that might be waiting for the channels
+ * to appear.
+ */
+static void increase_channel_count(struct nd_struct *nd, int n)
+{
+ struct ch_struct *ch;
+ struct device *classp;
+ char name[DEVICE_NAME_SIZE];
+ int ret;
+ u8 *buf;
+ int i;
+
+ for (i = nd->nd_chan_count; i < n; ++i) {
+ ch = nd->nd_chan + i;
+
+ /* FIXME: return a useful error instead! */
+ buf = kmalloc(TBUF_MAX, GFP_KERNEL);
+ if (!buf)
+ return;
+
+ if (ch->ch_tbuf)
+ pr_info_ratelimited("%s - ch_tbuf was not NULL\n",
+ __func__);
+
+ ch->ch_tbuf = buf;
+
+ buf = kmalloc(RBUF_MAX, GFP_KERNEL);
+ if (!buf)
+ return;
+
+ if (ch->ch_rbuf)
+ pr_info("%s - ch_rbuf was not NULL\n",
+ __func__);
+ ch->ch_rbuf = buf;
+
+ classp = tty_port_register_device(&ch->port,
+ nd->nd_serial_ttdriver, i,
+ NULL);
+
+ ch->ch_tun.un_sysfs = classp;
+ snprintf(name, DEVICE_NAME_SIZE, "tty_%d", i);
+
+ dgrp_create_tty_sysfs(&ch->ch_tun, classp);
+ ret = sysfs_create_link(&nd->nd_class_dev->kobj,
+ &classp->kobj, name);
+
+ /* NOTE: We don't support "cu" devices anymore,
+ * so you will notice we don't register them
+ * here anymore. */
+ if (dgrp_register_prdevices) {
+ classp = tty_register_device(nd->nd_xprint_ttdriver,
+ i, NULL);
+ ch->ch_pun.un_sysfs = classp;
+ snprintf(name, DEVICE_NAME_SIZE, "pr_%d", i);
+
+ dgrp_create_tty_sysfs(&ch->ch_pun, classp);
+ ret = sysfs_create_link(&nd->nd_class_dev->kobj,
+ &classp->kobj, name);
+ }
+
+ nd->nd_chan_count = i + 1;
+ wake_up_interruptible(&ch->ch_flag_wait);
+ }
+}
+
+/*
+ * Decrease the number of channels, and wake up any threads that might
+ * be waiting on the channels that vanished.
+ */
+static void decrease_channel_count(struct nd_struct *nd, int n)
+{
+ struct ch_struct *ch;
+ char name[DEVICE_NAME_SIZE];
+ int i;
+
+ for (i = nd->nd_chan_count - 1; i >= n; --i) {
+ ch = nd->nd_chan + i;
+
+ /*
+ * Make any open ports inoperative.
+ */
+ ch->ch_state = CS_IDLE;
+
+ ch->ch_otype = 0;
+ ch->ch_otype_waiting = 0;
+
+ /*
+ * Only "HANGUP" if we care about carrier
+ * transitions and we are already open.
+ */
+ if (ch->ch_open_count != 0) {
+ ch->ch_flag |= CH_HANGUP;
+ dgrp_carrier(ch);
+ }
+
+ /*
+ * Unlike the CH_HANGUP flag above, use another
+ * flag to indicate to the RealPort state machine
+ * that this port has disappeared.
+ */
+ if (ch->ch_open_count != 0)
+ ch->ch_flag |= CH_PORT_GONE;
+
+ wake_up_interruptible(&ch->ch_flag_wait);
+
+ nd->nd_chan_count = i;
+
+ kfree(ch->ch_tbuf);
+ ch->ch_tbuf = NULL;
+
+ kfree(ch->ch_rbuf);
+ ch->ch_rbuf = NULL;
+
+ nd->nd_chan_count = i;
+
+ dgrp_remove_tty_sysfs(ch->ch_tun.un_sysfs);
+ snprintf(name, DEVICE_NAME_SIZE, "tty_%d", i);
+ sysfs_remove_link(&nd->nd_class_dev->kobj, name);
+ tty_unregister_device(nd->nd_serial_ttdriver, i);
+
+ /*
+ * NOTE: We don't support "cu" devices anymore, so don't
+ * unregister them here anymore.
+ */
+
+ if (dgrp_register_prdevices) {
+ dgrp_remove_tty_sysfs(ch->ch_pun.un_sysfs);
+ snprintf(name, DEVICE_NAME_SIZE, "pr_%d", i);
+ sysfs_remove_link(&nd->nd_class_dev->kobj, name);
+ tty_unregister_device(nd->nd_xprint_ttdriver, i);
+ }
+ }
+}
+
+/**
+ * dgrp_chan_count() -- Adjust the node channel count.
+ * @nd: pointer to a node structure
+ * @n: new value for channel count
+ *
+ * Adjusts the node channel count. If new ports have appeared, it tries
+ * to signal those processes that might have been waiting for ports to
+ * appear. If ports have disappeared it tries to signal those processes
+ * that might be hung waiting for a response for the now non-existant port.
+ */
+static void dgrp_chan_count(struct nd_struct *nd, int n)
+{
+ if (n == nd->nd_chan_count)
+ return;
+
+ if (n > nd->nd_chan_count)
+ increase_channel_count(nd, n);
+
+ if (n < nd->nd_chan_count)
+ decrease_channel_count(nd, n);
+}
+
+/**
+ * dgrp_monitor() -- send data to the device monitor queue
+ * @nd: pointer to a node structure
+ * @buf: data to copy to the monitoring buffer
+ * @len: number of bytes to transfer to the buffer
+ *
+ * Called by the net device routines to send data to the device
+ * monitor queue. If the device monitor buffer is too full to
+ * accept the data, it waits until the buffer is ready.
+ */
+static void dgrp_monitor(struct nd_struct *nd, u8 *buf, int len)
+{
+ int n;
+ int r;
+ int rtn;
+
+ /*
+ * Grab monitor lock.
+ */
+ down(&nd->nd_mon_semaphore);
+
+ /*
+ * Loop while data remains.
+ */
+ while ((len > 0) && (nd->nd_mon_buf)) {
+ /*
+ * Determine the amount of available space left in the
+ * buffer. If there's none, wait until some appears.
+ */
+
+ n = (nd->nd_mon_out - nd->nd_mon_in - 1) & MON_MASK;
+
+ if (!n) {
+ nd->nd_mon_flag |= MON_WAIT_SPACE;
+
+ up(&nd->nd_mon_semaphore);
+
+ /*
+ * Go to sleep waiting until the condition becomes true.
+ */
+ rtn = wait_event_interruptible(nd->nd_mon_wqueue,
+ ((nd->nd_mon_flag & MON_WAIT_SPACE) == 0));
+
+/* FIXME: really ignore rtn? */
+
+ /*
+ * We can't exit here if we receive a signal, since
+ * to do so would trash the debug stream.
+ */
+
+ down(&nd->nd_mon_semaphore);
+
+ continue;
+ }
+
+ /*
+ * Copy as much data as will fit.
+ */
+
+ if (n > len)
+ n = len;
+
+ r = MON_MAX - nd->nd_mon_in;
+
+ if (r <= n) {
+ memcpy(nd->nd_mon_buf + nd->nd_mon_in, buf, r);
+
+ n -= r;
+
+ nd->nd_mon_in = 0;
+
+ buf += r;
+ len -= r;
+ }
+
+ memcpy(nd->nd_mon_buf + nd->nd_mon_in, buf, n);
+
+ nd->nd_mon_in += n;
+
+ buf += n;
+ len -= n;
+
+ if (nd->nd_mon_in >= MON_MAX)
+ pr_info_ratelimited("%s - nd_mon_in (%i) >= MON_MAX\n",
+ __func__, nd->nd_mon_in);
+
+ /*
+ * Wakeup any thread waiting for data
+ */
+
+ if (nd->nd_mon_flag & MON_WAIT_DATA) {
+ nd->nd_mon_flag &= ~MON_WAIT_DATA;
+ wake_up_interruptible(&nd->nd_mon_wqueue);
+ }
+ }
+
+ /*
+ * Release the monitor lock.
+ */
+ up(&nd->nd_mon_semaphore);
+}
+
+/**
+ * dgrp_encode_time() -- Encodes rpdump time into a 4-byte quantity.
+ * @nd: pointer to a node structure
+ * @buf: destination buffer
+ *
+ * Encodes "rpdump" time into a 4-byte quantity. Time is measured since
+ * open.
+ */
+static void dgrp_encode_time(struct nd_struct *nd, u8 *buf)
+{
+ ulong t;
+
+ /*
+ * Convert time in HZ since open to time in milliseconds
+ * since open.
+ */
+ t = jiffies - nd->nd_mon_lbolt;
+ t = 1000 * (t / HZ) + 1000 * (t % HZ) / HZ;
+
+ put_unaligned_be32((uint)(t & 0xffffffff), buf);
+}
+
+
+
+/**
+ * dgrp_monitor_message() -- Builds a rpdump style message.
+ * @nd: pointer to a node structure
+ * @message: destination buffer
+ */
+static void dgrp_monitor_message(struct nd_struct *nd, char *message)
+{
+ u8 header[7];
+ int n;
+
+ header[0] = RPDUMP_MESSAGE;
+
+ dgrp_encode_time(nd, header + 1);
+
+ n = strlen(message);
+
+ put_unaligned_be16(n, header + 5);
+
+ dgrp_monitor(nd, header, sizeof(header));
+ dgrp_monitor(nd, (u8 *) message, n);
+}
+
+
+
+/**
+ * dgrp_monitor_reset() -- Note a reset in the monitoring buffer.
+ * @nd: pointer to a node structure
+ */
+static void dgrp_monitor_reset(struct nd_struct *nd)
+{
+ u8 header[5];
+
+ header[0] = RPDUMP_RESET;
+
+ dgrp_encode_time(nd, header + 1);
+
+ dgrp_monitor(nd, header, sizeof(header));
+}
+
+/**
+ * dgrp_monitor_data() -- builds a monitor data packet
+ * @nd: pointer to a node structure
+ * @type: type of message to be logged
+ * @buf: data to be logged
+ * @size: number of bytes in the buffer
+ */
+static void dgrp_monitor_data(struct nd_struct *nd, u8 type, u8 *buf, int size)
+{
+ u8 header[7];
+
+ header[0] = type;
+
+ dgrp_encode_time(nd, header + 1);
+
+ put_unaligned_be16(size, header + 5);
+
+ dgrp_monitor(nd, header, sizeof(header));
+ dgrp_monitor(nd, buf, size);
+}
+
+static int alloc_nd_buffers(struct nd_struct *nd)
+{
+
+ nd->nd_iobuf = NULL;
+ nd->nd_writebuf = NULL;
+ nd->nd_inputbuf = NULL;
+ nd->nd_inputflagbuf = NULL;
+
+ /*
+ * Allocate the network read/write buffer.
+ */
+ nd->nd_iobuf = kzalloc(UIO_MAX + 10, GFP_KERNEL);
+ if (!nd->nd_iobuf)
+ goto out_err;
+
+ /*
+ * Allocate a buffer for doing the copy from user space to
+ * kernel space in the write routines.
+ */
+ nd->nd_writebuf = kzalloc(WRITEBUFLEN, GFP_KERNEL);
+ if (!nd->nd_writebuf)
+ goto out_err;
+
+ /*
+ * Allocate a buffer for doing the copy from kernel space to
+ * tty buffer space in the read routines.
+ */
+ nd->nd_inputbuf = kzalloc(MYFLIPLEN, GFP_KERNEL);
+ if (!nd->nd_inputbuf)
+ goto out_err;
+
+ /*
+ * Allocate a buffer for doing the copy from kernel space to
+ * tty buffer space in the read routines.
+ */
+ nd->nd_inputflagbuf = kzalloc(MYFLIPLEN, GFP_KERNEL);
+ if (!nd->nd_inputflagbuf)
+ goto out_err;
+
+ return 0;
+
+out_err:
+ kfree(nd->nd_iobuf);
+ kfree(nd->nd_writebuf);
+ kfree(nd->nd_inputbuf);
+ kfree(nd->nd_inputflagbuf);
+ return -ENOMEM;
+}
+
+/*
+ * dgrp_net_open() -- Open the NET device for a particular PortServer
+ */
+static int dgrp_net_open(struct inode *inode, struct file *file)
+{
+ struct nd_struct *nd;
+ struct proc_dir_entry *de;
+ ulong lock_flags;
+ int rtn;
+
+ rtn = try_module_get(THIS_MODULE);
+ if (!rtn)
+ return -EAGAIN;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ rtn = -EPERM;
+ goto done;
+ }
+
+ /*
+ * Make sure that the "private_data" field hasn't already been used.
+ */
+ if (file->private_data) {
+ rtn = -EINVAL;
+ goto done;
+ }
+
+ /*
+ * Get the node pointer, and fail if it doesn't exist.
+ */
+ de = PDE(inode);
+ if (!de) {
+ rtn = -ENXIO;
+ goto done;
+ }
+
+ nd = (struct nd_struct *) de->data;
+ if (!nd) {
+ rtn = -ENXIO;
+ goto done;
+ }
+
+ file->private_data = (void *) nd;
+
+ /*
+ * Grab the NET lock.
+ */
+ down(&nd->nd_net_semaphore);
+
+ if (nd->nd_state != NS_CLOSED) {
+ rtn = -EBUSY;
+ goto unlock;
+ }
+
+ /*
+ * Initialize the link speed parameters.
+ */
+
+ nd->nd_link.lk_fast_rate = UIO_MAX;
+ nd->nd_link.lk_slow_rate = UIO_MAX;
+
+ nd->nd_link.lk_fast_delay = 1000;
+ nd->nd_link.lk_slow_delay = 1000;
+
+ nd->nd_link.lk_header_size = 46;
+
+
+ rtn = alloc_nd_buffers(nd);
+ if (rtn)
+ goto unlock;
+
+ /*
+ * The port is now open, so move it to the IDLE state
+ */
+ dgrp_net_idle(nd);
+
+ nd->nd_tx_time = jiffies;
+
+ /*
+ * If the polling routing is not running, start it running here
+ */
+ spin_lock_irqsave(&dgrp_poll_data.poll_lock, lock_flags);
+
+ if (!dgrp_poll_data.node_active_count) {
+ dgrp_poll_data.node_active_count = 2;
+ dgrp_poll_data.timer.expires = jiffies +
+ dgrp_poll_tick * HZ / 1000;
+ add_timer(&dgrp_poll_data.timer);
+ }
+
+ spin_unlock_irqrestore(&dgrp_poll_data.poll_lock, lock_flags);
+
+ dgrp_monitor_message(nd, "Net Open");
+
+unlock:
+ /*
+ * Release the NET lock.
+ */
+ up(&nd->nd_net_semaphore);
+
+done:
+ if (rtn)
+ module_put(THIS_MODULE);
+
+ return rtn;
+}
+
+/* dgrp_net_release() -- close the NET device for a particular PortServer */
+static int dgrp_net_release(struct inode *inode, struct file *file)
+{
+ struct nd_struct *nd;
+ ulong lock_flags;
+
+ nd = (struct nd_struct *)(file->private_data);
+ if (!nd)
+ goto done;
+
+/* TODO : historical locking placeholder */
+/*
+ * In the HPUX version of the RealPort driver (which served as a basis
+ * for this driver) this locking code was used. Saved if ever we need
+ * to review the locking under Linux.
+ */
+/* spinlock(&nd->nd_lock); */
+
+
+ /*
+ * Grab the NET lock.
+ */
+ down(&nd->nd_net_semaphore);
+
+ /*
+ * Before "closing" the internal connection, make sure all
+ * ports are "idle".
+ */
+ dgrp_net_idle(nd);
+
+ nd->nd_state = NS_CLOSED;
+ nd->nd_flag = 0;
+
+ /*
+ * TODO ... must the wait queue be reset on close?
+ * should any pending waiters be reset?
+ * Let's decide to assert that the waitq is empty... and see
+ * how soon we break.
+ */
+ if (waitqueue_active(&nd->nd_tx_waitq))
+ pr_info("%s - expected waitqueue_active to be false\n",
+ __func__);
+
+ nd->nd_send = 0;
+
+ kfree(nd->nd_iobuf);
+ nd->nd_iobuf = NULL;
+
+/* TODO : historical locking placeholder */
+/*
+ * In the HPUX version of the RealPort driver (which served as a basis
+ * for this driver) this locking code was used. Saved if ever we need
+ * to review the locking under Linux.
+ */
+/* spinunlock( &nd->nd_lock ); */
+
+
+ kfree(nd->nd_writebuf);
+ nd->nd_writebuf = NULL;
+
+ kfree(nd->nd_inputbuf);
+ nd->nd_inputbuf = NULL;
+
+ kfree(nd->nd_inputflagbuf);
+ nd->nd_inputflagbuf = NULL;
+
+/* TODO : historical locking placeholder */
+/*
+ * In the HPUX version of the RealPort driver (which served as a basis
+ * for this driver) this locking code was used. Saved if ever we need
+ * to review the locking under Linux.
+ */
+/* spinlock(&nd->nd_lock); */
+
+ /*
+ * Set the active port count to zero.
+ */
+ dgrp_chan_count(nd, 0);
+
+/* TODO : historical locking placeholder */
+/*
+ * In the HPUX version of the RealPort driver (which served as a basis
+ * for this driver) this locking code was used. Saved if ever we need
+ * to review the locking under Linux.
+ */
+/* spinunlock(&nd->nd_lock); */
+
+ /*
+ * Release the NET lock.
+ */
+ up(&nd->nd_net_semaphore);
+
+ /*
+ * Cause the poller to stop scheduling itself if this is
+ * the last active node.
+ */
+ spin_lock_irqsave(&dgrp_poll_data.poll_lock, lock_flags);
+
+ if (dgrp_poll_data.node_active_count == 2) {
+ del_timer(&dgrp_poll_data.timer);
+ dgrp_poll_data.node_active_count = 0;
+ }
+
+ spin_unlock_irqrestore(&dgrp_poll_data.poll_lock, lock_flags);
+
+done:
+ down(&nd->nd_net_semaphore);
+
+ dgrp_monitor_message(nd, "Net Close");
+
+ up(&nd->nd_net_semaphore);
+
+ module_put(THIS_MODULE);
+ file->private_data = NULL;
+ return 0;
+}
+
+/* used in dgrp_send to setup command header */
+static inline u8 *set_cmd_header(u8 *b, u8 port, u8 cmd)
+{
+ *b++ = 0xb0 + (port & 0x0f);
+ *b++ = cmd;
+ return b;
+}
+
+/**
+ * dgrp_send() -- build a packet for transmission to the server
+ * @nd: pointer to a node structure
+ * @tmax: maximum bytes to transmit
+ *
+ * returns number of bytes sent
+ */
+static int dgrp_send(struct nd_struct *nd, long tmax)
+{
+ struct ch_struct *ch = nd->nd_chan;
+ u8 *b;
+ u8 *buf;
+ u8 *mbuf;
+ u8 port;
+ int mod;
+ long send;
+ int maxport;
+ long lastport = -1;
+ ushort rwin;
+ long in;
+ ushort n;
+ long t;
+ long ttotal;
+ long tchan;
+ long tsend;
+ ushort tsafe;
+ long work;
+ long send_sync;
+ long wanted_sync_port = -1;
+ ushort tdata[CHAN_MAX];
+ long used_buffer;
+
+ mbuf = nd->nd_iobuf + UIO_BASE;
+ buf = b = mbuf;
+
+ send_sync = nd->nd_link.lk_slow_rate < UIO_MAX;
+
+ ttotal = 0;
+ tchan = 0;
+
+ memset(tdata, 0, sizeof(tdata));
+
+
+ /*
+ * If there are any outstanding requests to be serviced,
+ * service them here.
+ */
+ if (nd->nd_send & NR_PASSWORD) {
+
+ /*
+ * Send Password response.
+ */
+
+ b[0] = 0xfc;
+ b[1] = 0x20;
+ put_unaligned_be16(strlen(nd->password), b + 2);
+ b += 4;
+ b += strlen(nd->password);
+ nd->nd_send &= ~(NR_PASSWORD);
+ }
+
+
+ /*
+ * Loop over all modules to generate commands, and determine
+ * the amount of data queued for transmit.
+ */
+
+ for (mod = 0, port = 0; port < nd->nd_chan_count; mod++) {
+ /*
+ * If this is not the current module, enter a module select
+ * code in the buffer.
+ */
+
+ if (mod != nd->nd_tx_module)
+ mbuf = ++b;
+
+ /*
+ * Loop to process one module.
+ */
+
+ maxport = port + 16;
+
+ if (maxport > nd->nd_chan_count)
+ maxport = nd->nd_chan_count;
+
+ for (; port < maxport; port++, ch++) {
+ /*
+ * Switch based on channel state.
+ */
+
+ switch (ch->ch_state) {
+ /*
+ * Send requests when the port is closed, and there
+ * are no Open, Close or Cancel requests expected.
+ */
+
+ case CS_IDLE:
+ /*
+ * Wait until any open error code
+ * has been delivered to all
+ * associated ports.
+ */
+
+ if (ch->ch_open_error) {
+ if (ch->ch_wait_count[ch->ch_otype]) {
+ work = 1;
+ break;
+ }
+
+ ch->ch_open_error = 0;
+ }
+
+ /*
+ * Wait until the channel HANGUP flag is reset
+ * before sending the first open. We can only
+ * get to this state after a server disconnect.
+ */
+
+ if ((ch->ch_flag & CH_HANGUP) != 0)
+ break;
+
+ /*
+ * If recovering from a TCP disconnect, or if
+ * there is an immediate open pending, send an
+ * Immediate Open request.
+ */
+ if ((ch->ch_flag & CH_PORT_GONE) ||
+ ch->ch_wait_count[OTYPE_IMMEDIATE] != 0) {
+ b = set_cmd_header(b, port, 10);
+ *b++ = 0;
+
+ ch->ch_state = CS_WAIT_OPEN;
+ ch->ch_otype = OTYPE_IMMEDIATE;
+ break;
+ }
+
+ /*
+ * If there is no Persistent or Incoming Open on the wait
+ * list in the server, and a thread is waiting for a
+ * Persistent or Incoming Open, send a Persistent or Incoming
+ * Open Request.
+ */
+ if (ch->ch_otype_waiting == 0) {
+ if (ch->ch_wait_count[OTYPE_PERSISTENT] != 0) {
+ b = set_cmd_header(b, port, 10);
+ *b++ = 1;
+
+ ch->ch_state = CS_WAIT_OPEN;
+ ch->ch_otype = OTYPE_PERSISTENT;
+ } else if (ch->ch_wait_count[OTYPE_INCOMING] != 0) {
+ b = set_cmd_header(b, port, 10);
+ *b++ = 2;
+
+ ch->ch_state = CS_WAIT_OPEN;
+ ch->ch_otype = OTYPE_INCOMING;
+ }
+ break;
+ }
+
+ /*
+ * If a Persistent or Incoming Open is pending in
+ * the server, but there is no longer an open
+ * thread waiting for it, cancel the request.
+ */
+
+ if (ch->ch_wait_count[ch->ch_otype_waiting] == 0) {
+ b = set_cmd_header(b, port, 10);
+ *b++ = 4;
+
+ ch->ch_state = CS_WAIT_CANCEL;
+ ch->ch_otype = ch->ch_otype_waiting;
+ }
+ break;
+
+ /*
+ * Send port parameter queries.
+ */
+ case CS_SEND_QUERY:
+ /*
+ * Clear out all FEP state that might remain
+ * from the last connection.
+ */
+
+ ch->ch_flag |= CH_PARAM;
+
+ ch->ch_flag &= ~CH_RX_FLUSH;
+
+ ch->ch_expect = 0;
+
+ ch->ch_s_tin = 0;
+ ch->ch_s_tpos = 0;
+ ch->ch_s_tsize = 0;
+ ch->ch_s_treq = 0;
+ ch->ch_s_elast = 0;
+
+ ch->ch_s_rin = 0;
+ ch->ch_s_rwin = 0;
+ ch->ch_s_rsize = 0;
+
+ ch->ch_s_tmax = 0;
+ ch->ch_s_ttime = 0;
+ ch->ch_s_rmax = 0;
+ ch->ch_s_rtime = 0;
+ ch->ch_s_rlow = 0;
+ ch->ch_s_rhigh = 0;
+
+ ch->ch_s_brate = 0;
+ ch->ch_s_iflag = 0;
+ ch->ch_s_cflag = 0;
+ ch->ch_s_oflag = 0;
+ ch->ch_s_xflag = 0;
+
+ ch->ch_s_mout = 0;
+ ch->ch_s_mflow = 0;
+ ch->ch_s_mctrl = 0;
+ ch->ch_s_xon = 0;
+ ch->ch_s_xoff = 0;
+ ch->ch_s_lnext = 0;
+ ch->ch_s_xxon = 0;
+ ch->ch_s_xxoff = 0;
+
+ /* Send Sequence Request */
+ b = set_cmd_header(b, port, 14);
+
+ /* Configure Event Conditions Packet */
+ b = set_cmd_header(b, port, 42);
+ put_unaligned_be16(0x02c0, b);
+ b += 2;
+ *b++ = (DM_DTR | DM_RTS | DM_CTS |
+ DM_DSR | DM_RI | DM_CD);
+
+ /* Send Status Request */
+ b = set_cmd_header(b, port, 16);
+
+ /* Send Buffer Request */
+ b = set_cmd_header(b, port, 20);
+
+ /* Send Port Capability Request */
+ b = set_cmd_header(b, port, 22);
+
+ ch->ch_expect = (RR_SEQUENCE |
+ RR_STATUS |
+ RR_BUFFER |
+ RR_CAPABILITY);
+
+ ch->ch_state = CS_WAIT_QUERY;
+
+ /* Raise modem signals */
+ b = set_cmd_header(b, port, 44);
+
+ if (ch->ch_flag & CH_PORT_GONE)
+ ch->ch_s_mout = ch->ch_mout;
+ else
+ ch->ch_s_mout = ch->ch_mout = DM_DTR | DM_RTS;
+
+ *b++ = ch->ch_mout;
+ *b++ = ch->ch_s_mflow = 0;
+ *b++ = ch->ch_s_mctrl = ch->ch_mctrl = 0;
+
+ if (ch->ch_flag & CH_PORT_GONE)
+ ch->ch_flag &= ~CH_PORT_GONE;
+
+ break;
+
+ /*
+ * Handle normal open and ready mode.
+ */
+
+ case CS_READY:
+
+ /*
+ * If the port is not open, and there are no
+ * no longer any ports requesting an open,
+ * then close the port.
+ */
+
+ if (ch->ch_open_count == 0 &&
+ ch->ch_wait_count[ch->ch_otype] == 0) {
+ goto send_close;
+ }
+
+ /*
+ * Process waiting input.
+ *
+ * If there is no one to read it, discard the data.
+ *
+ * Otherwise if we are not in fastcook mode, or if there is a
+ * fastcook thread waiting for data, send the data to the
+ * line discipline.
+ */
+ if (ch->ch_rin != ch->ch_rout) {
+ if (ch->ch_tun.un_open_count == 0 ||
+ (ch->ch_tun.un_flag & UN_CLOSING) ||
+ (ch->ch_cflag & CF_CREAD) == 0) {
+ ch->ch_rout = ch->ch_rin;
+ } else if ((ch->ch_flag & CH_FAST_READ) == 0 ||
+ ch->ch_inwait != 0) {
+ dgrp_input(ch);
+
+ if (ch->ch_rin != ch->ch_rout)
+ work = 1;
+ }
+ }
+
+ /*
+ * Handle receive flush, and changes to
+ * server port parameters.
+ */
+
+ if (ch->ch_flag & (CH_RX_FLUSH | CH_PARAM)) {
+ /*
+ * If we are in receive flush mode,
+ * and enough data has gone by, reset
+ * receive flush mode.
+ */
+ if (ch->ch_flag & CH_RX_FLUSH) {
+ if (((ch->ch_flush_seq - nd->nd_seq_out) & SEQ_MASK) >
+ ((nd->nd_seq_in - nd->nd_seq_out) & SEQ_MASK))
+ ch->ch_flag &= ~CH_RX_FLUSH;
+ else
+ work = 1;
+ }
+
+ /*
+ * Send TMAX, TTIME.
+ */
+
+ if (ch->ch_s_tmax != ch->ch_tmax ||
+ ch->ch_s_ttime != ch->ch_ttime) {
+ b = set_cmd_header(b, port, 48);
+
+ ch->ch_s_tmax = ch->ch_tmax;
+ ch->ch_s_ttime = ch->ch_ttime;
+
+ put_unaligned_be16(ch->ch_s_tmax,
+ b);
+ b += 2;
+
+ put_unaligned_be16(ch->ch_s_ttime,
+ b);
+ b += 2;
+ }
+
+ /*
+ * Send RLOW, RHIGH.
+ */
+
+ if (ch->ch_s_rlow != ch->ch_rlow ||
+ ch->ch_s_rhigh != ch->ch_rhigh) {
+ b = set_cmd_header(b, port, 45);
+
+ ch->ch_s_rlow = ch->ch_rlow;
+ ch->ch_s_rhigh = ch->ch_rhigh;
+
+ put_unaligned_be16(ch->ch_s_rlow,
+ b);
+ b += 2;
+
+ put_unaligned_be16(ch->ch_s_rhigh,
+ b);
+ b += 2;
+ }
+
+ /*
+ * Send BRATE, CFLAG, IFLAG,
+ * OFLAG, XFLAG.
+ */
+
+ if (ch->ch_s_brate != ch->ch_brate ||
+ ch->ch_s_cflag != ch->ch_cflag ||
+ ch->ch_s_iflag != ch->ch_iflag ||
+ ch->ch_s_oflag != ch->ch_oflag ||
+ ch->ch_s_xflag != ch->ch_xflag) {
+ b = set_cmd_header(b, port, 40);
+
+ ch->ch_s_brate = ch->ch_brate;
+ ch->ch_s_cflag = ch->ch_cflag;
+ ch->ch_s_iflag = ch->ch_iflag;
+ ch->ch_s_oflag = ch->ch_oflag;
+ ch->ch_s_xflag = ch->ch_xflag;
+
+ put_unaligned_be16(ch->ch_s_brate,
+ b);
+ b += 2;
+
+ put_unaligned_be16(ch->ch_s_cflag,
+ b);
+ b += 2;
+
+ put_unaligned_be16(ch->ch_s_iflag,
+ b);
+ b += 2;
+
+ put_unaligned_be16(ch->ch_s_oflag,
+ b);
+ b += 2;
+
+ put_unaligned_be16(ch->ch_s_xflag,
+ b);
+ b += 2;
+ }
+
+ /*
+ * Send MOUT, MFLOW, MCTRL.
+ */
+
+ if (ch->ch_s_mout != ch->ch_mout ||
+ ch->ch_s_mflow != ch->ch_mflow ||
+ ch->ch_s_mctrl != ch->ch_mctrl) {
+ b = set_cmd_header(b, port, 44);
+
+ *b++ = ch->ch_s_mout = ch->ch_mout;
+ *b++ = ch->ch_s_mflow = ch->ch_mflow;
+ *b++ = ch->ch_s_mctrl = ch->ch_mctrl;
+ }
+
+ /*
+ * Send Flow control characters.
+ */
+
+ if (ch->ch_s_xon != ch->ch_xon ||
+ ch->ch_s_xoff != ch->ch_xoff ||
+ ch->ch_s_lnext != ch->ch_lnext ||
+ ch->ch_s_xxon != ch->ch_xxon ||
+ ch->ch_s_xxoff != ch->ch_xxoff) {
+ b = set_cmd_header(b, port, 46);
+
+ *b++ = ch->ch_s_xon = ch->ch_xon;
+ *b++ = ch->ch_s_xoff = ch->ch_xoff;
+ *b++ = ch->ch_s_lnext = ch->ch_lnext;
+ *b++ = ch->ch_s_xxon = ch->ch_xxon;
+ *b++ = ch->ch_s_xxoff = ch->ch_xxoff;
+ }
+
+ /*
+ * Send RMAX, RTIME.
+ */
+
+ if (ch->ch_s_rmax != ch->ch_rmax ||
+ ch->ch_s_rtime != ch->ch_rtime) {
+ b = set_cmd_header(b, port, 47);
+
+ ch->ch_s_rmax = ch->ch_rmax;
+ ch->ch_s_rtime = ch->ch_rtime;
+
+ put_unaligned_be16(ch->ch_s_rmax,
+ b);
+ b += 2;
+
+ put_unaligned_be16(ch->ch_s_rtime,
+ b);
+ b += 2;
+ }
+
+ ch->ch_flag &= ~CH_PARAM;
+ wake_up_interruptible(&ch->ch_flag_wait);
+ }
+
+
+ /*
+ * Handle action commands.
+ */
+
+ if (ch->ch_send != 0) {
+ /* int send = ch->ch_send & ~ch->ch_expect; */
+ send = ch->ch_send & ~ch->ch_expect;
+
+ /* Send character immediate */
+ if ((send & RR_TX_ICHAR) != 0) {
+ b = set_cmd_header(b, port, 60);
+
+ *b++ = ch->ch_xon;
+ ch->ch_expect |= RR_TX_ICHAR;
+ }
+
+ /* BREAK request */
+ if ((send & RR_TX_BREAK) != 0) {
+ if (ch->ch_break_time != 0) {
+ b = set_cmd_header(b, port, 61);
+ put_unaligned_be16(ch->ch_break_time,
+ b);
+ b += 2;
+
+ ch->ch_expect |= RR_TX_BREAK;
+ ch->ch_break_time = 0;
+ } else {
+ ch->ch_send &= ~RR_TX_BREAK;
+ ch->ch_flag &= ~CH_TX_BREAK;
+ wake_up_interruptible(&ch->ch_flag_wait);
+ }
+ }
+
+ /*
+ * Flush input/output buffers.
+ */
+
+ if ((send & (RR_RX_FLUSH | RR_TX_FLUSH)) != 0) {
+ b = set_cmd_header(b, port, 62);
+
+ *b++ = ((send & RR_TX_FLUSH) == 0 ? 1 :
+ (send & RR_RX_FLUSH) == 0 ? 2 : 3);
+
+ if (send & RR_RX_FLUSH) {
+ ch->ch_flush_seq = nd->nd_seq_in;
+ ch->ch_flag |= CH_RX_FLUSH;
+ work = 1;
+ send_sync = 1;
+ wanted_sync_port = port;
+ }
+
+ ch->ch_send &= ~(RR_RX_FLUSH | RR_TX_FLUSH);
+ }
+
+ /* Pause input/output */
+ if ((send & (RR_RX_STOP | RR_TX_STOP)) != 0) {
+ b = set_cmd_header(b, port, 63);
+ *b = 0;
+
+ if ((send & RR_TX_STOP) != 0)
+ *b |= EV_OPU;
+
+ if ((send & RR_RX_STOP) != 0)
+ *b |= EV_IPU;
+
+ b++;
+
+ ch->ch_send &= ~(RR_RX_STOP | RR_TX_STOP);
+ }
+
+ /* Start input/output */
+ if ((send & (RR_RX_START | RR_TX_START)) != 0) {
+ b = set_cmd_header(b, port, 64);
+ *b = 0;
+
+ if ((send & RR_TX_START) != 0)
+ *b |= EV_OPU | EV_OPS | EV_OPX;
+
+ if ((send & RR_RX_START) != 0)
+ *b |= EV_IPU | EV_IPS;
+
+ b++;
+
+ ch->ch_send &= ~(RR_RX_START | RR_TX_START);
+ }
+ }
+
+
+ /*
+ * Send a window sequence to acknowledge received data.
+ */
+
+ rwin = (ch->ch_s_rin +
+ ((ch->ch_rout - ch->ch_rin - 1) & RBUF_MASK));
+
+ n = (rwin - ch->ch_s_rwin) & 0xffff;
+
+ if (n >= RBUF_MAX / 4) {
+ b[0] = 0xa0 + (port & 0xf);
+ ch->ch_s_rwin = rwin;
+ put_unaligned_be16(rwin, b + 1);
+ b += 3;
+ }
+
+ /*
+ * If the terminal is waiting on LOW
+ * water or EMPTY, and the condition
+ * is now satisfied, call the line
+ * discipline to put more data in the
+ * buffer.
+ */
+
+ n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK;
+
+ if ((ch->ch_tun.un_flag & (UN_EMPTY|UN_LOW)) != 0) {
+ if ((ch->ch_tun.un_flag & UN_LOW) != 0 ?
+ (n <= TBUF_LOW) :
+ (n == 0 && ch->ch_s_tpos == ch->ch_s_tin)) {
+ ch->ch_tun.un_flag &= ~(UN_EMPTY|UN_LOW);
+
+ if (waitqueue_active(&((ch->ch_tun.un_tty)->write_wait)))
+ wake_up_interruptible(&((ch->ch_tun.un_tty)->write_wait));
+ tty_wakeup(ch->ch_tun.un_tty);
+ n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK;
+ }
+ }
+
+ /*
+ * If the printer is waiting on LOW
+ * water, TIME, EMPTY or PWAIT, and is
+ * now ready to put more data in the
+ * buffer, call the line discipline to
+ * do the job.
+ */
+
+ if (ch->ch_pun.un_open_count &&
+ (ch->ch_pun.un_flag &
+ (UN_EMPTY|UN_TIME|UN_LOW|UN_PWAIT)) != 0) {
+
+ if ((ch->ch_pun.un_flag & UN_LOW) != 0 ?
+ (n <= TBUF_LOW) :
+ (ch->ch_pun.un_flag & UN_TIME) != 0 ?
+ ((jiffies - ch->ch_waketime) >= 0) :
+ (n == 0 && ch->ch_s_tpos == ch->ch_s_tin) &&
+ ((ch->ch_pun.un_flag & UN_EMPTY) != 0 ||
+ ((ch->ch_tun.un_open_count &&
+ ch->ch_tun.un_tty->ops->chars_in_buffer) ?
+ (ch->ch_tun.un_tty->ops->chars_in_buffer)(ch->ch_tun.un_tty) == 0
+ : 1
+ )
+ )) {
+ ch->ch_pun.un_flag &= ~(UN_EMPTY | UN_TIME | UN_LOW | UN_PWAIT);
+
+ if (waitqueue_active(&((ch->ch_pun.un_tty)->write_wait)))
+ wake_up_interruptible(&((ch->ch_pun.un_tty)->write_wait));
+ tty_wakeup(ch->ch_pun.un_tty);
+ n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK;
+
+ } else if ((ch->ch_pun.un_flag & UN_TIME) != 0) {
+ work = 1;
+ }
+ }
+
+
+ /*
+ * Determine the max number of bytes
+ * this port can send, including
+ * packet header overhead.
+ */
+
+ t = ((ch->ch_s_tsize + ch->ch_s_tpos - ch->ch_s_tin) & 0xffff);
+
+ if (n > t)
+ n = t;
+
+ if (n != 0) {
+ n += (n <= 8 ? 1 : n <= 255 ? 2 : 3);
+
+ tdata[tchan++] = n;
+ ttotal += n;
+ }
+ break;
+
+ /*
+ * Close the port.
+ */
+
+send_close:
+ case CS_SEND_CLOSE:
+ b = set_cmd_header(b, port, 10);
+ if (ch->ch_otype == OTYPE_IMMEDIATE)
+ *b++ = 3;
+ else
+ *b++ = 4;
+
+ ch->ch_state = CS_WAIT_CLOSE;
+ break;
+
+ /*
+ * Wait for a previous server request.
+ */
+
+ case CS_WAIT_OPEN:
+ case CS_WAIT_CANCEL:
+ case CS_WAIT_FAIL:
+ case CS_WAIT_QUERY:
+ case CS_WAIT_CLOSE:
+ break;
+
+ default:
+ pr_info("%s - unexpected channel state (%i)\n",
+ __func__, ch->ch_state);
+ }
+ }
+
+ /*
+ * If a module select code is needed, drop one in. If space
+ * was reserved for one, but none is needed, recover the space.
+ */
+
+ if (mod != nd->nd_tx_module) {
+ if (b != mbuf) {
+ mbuf[-1] = 0xf0 | mod;
+ nd->nd_tx_module = mod;
+ } else {
+ b--;
+ }
+ }
+ }
+
+ /*
+ * Adjust "tmax" so that under worst case conditions we do
+ * not overflow either the daemon buffer or the internal
+ * buffer in the loop that follows. Leave a safe area
+ * of 64 bytes so we start getting asserts before we start
+ * losing data or clobbering memory.
+ */
+
+ n = UIO_MAX - UIO_BASE;
+
+ if (tmax > n)
+ tmax = n;
+
+ tmax -= 64;
+
+ tsafe = tmax;
+
+ /*
+ * Allocate space for 5 Module Selects, 1 Sequence Request,
+ * and 1 Set TREQ for each active channel.
+ */
+
+ tmax -= 5 + 3 + 4 * nd->nd_chan_count;
+
+ /*
+ * Further reduce "tmax" to the available transmit credit.
+ * Note that this is a soft constraint; The transmit credit
+ * can go negative for a time and then recover.
+ */
+
+ n = nd->nd_tx_deposit - nd->nd_tx_charge - nd->nd_link.lk_header_size;
+
+ if (tmax > n)
+ tmax = n;
+
+ /*
+ * Finally reduce tmax by the number of bytes already in
+ * the buffer.
+ */
+
+ tmax -= b - buf;
+
+ /*
+ * Suspend data transmit unless every ready channel can send
+ * at least 1 character.
+ */
+ if (tmax < 2 * nd->nd_chan_count) {
+ tsend = 1;
+
+ } else if (tchan > 1 && ttotal > tmax) {
+
+ /*
+ * If transmit is limited by the credit budget, find the
+ * largest number of characters we can send without driving
+ * the credit negative.
+ */
+
+ long tm = tmax;
+ int tc = tchan;
+ int try;
+
+ tsend = tm / tc;
+
+ for (try = 0; try < 3; try++) {
+ int i;
+ int c = 0;
+
+ for (i = 0; i < tc; i++) {
+ if (tsend < tdata[i])
+ tdata[c++] = tdata[i];
+ else
+ tm -= tdata[i];
+ }
+
+ if (c == tc)
+ break;
+
+ tsend = tm / c;
+
+ if (c == 1)
+ break;
+
+ tc = c;
+ }
+
+ tsend = tm / nd->nd_chan_count;
+
+ if (tsend < 2)
+ tsend = 1;
+
+ } else {
+ /*
+ * If no budgetary constraints, or only one channel ready
+ * to send, set the character limit to the remaining
+ * buffer size.
+ */
+
+ tsend = tmax;
+ }
+
+ tsend -= (tsend <= 9) ? 1 : (tsend <= 257) ? 2 : 3;
+
+ /*
+ * Loop over all channels, sending queued data.
+ */
+
+ port = 0;
+ ch = nd->nd_chan;
+ used_buffer = tmax;
+
+ for (mod = 0; port < nd->nd_chan_count; mod++) {
+ /*
+ * If this is not the current module, enter a module select
+ * code in the buffer.
+ */
+
+ if (mod != nd->nd_tx_module)
+ mbuf = ++b;
+
+ /*
+ * Loop to process one module.
+ */
+
+ maxport = port + 16;
+
+ if (maxport > nd->nd_chan_count)
+ maxport = nd->nd_chan_count;
+
+ for (; port < maxport; port++, ch++) {
+ if (ch->ch_state != CS_READY)
+ continue;
+
+ lastport = port;
+
+ n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK;
+
+ /*
+ * If there is data that can be sent, send it.
+ */
+
+ if (n != 0 && used_buffer > 0) {
+ t = (ch->ch_s_tsize + ch->ch_s_tpos - ch->ch_s_tin) & 0xffff;
+
+ if (n > t)
+ n = t;
+
+ if (n > tsend) {
+ work = 1;
+ n = tsend;
+ }
+
+ if (n > used_buffer) {
+ work = 1;
+ n = used_buffer;
+ }
+
+ if (n <= 0)
+ continue;
+
+ /*
+ * Create the correct size transmit header,
+ * depending on the amount of data to transmit.
+ */
+
+ if (n <= 8) {
+
+ b[0] = ((n - 1) << 4) + (port & 0xf);
+ b += 1;
+
+ } else if (n <= 255) {
+
+ b[0] = 0x80 + (port & 0xf);
+ b[1] = n;
+ b += 2;
+
+ } else {
+
+ b[0] = 0x90 + (port & 0xf);
+ put_unaligned_be16(n, b + 1);
+ b += 3;
+ }
+
+ ch->ch_s_tin = (ch->ch_s_tin + n) & 0xffff;
+
+ /*
+ * Copy transmit data to the packet.
+ */
+
+ t = TBUF_MAX - ch->ch_tout;
+
+ if (n >= t) {
+ memcpy(b, ch->ch_tbuf + ch->ch_tout, t);
+ b += t;
+ n -= t;
+ used_buffer -= t;
+ ch->ch_tout = 0;
+ }
+
+ memcpy(b, ch->ch_tbuf + ch->ch_tout, n);
+ b += n;
+ used_buffer -= n;
+ ch->ch_tout += n;
+ n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK;
+ }
+
+ /*
+ * Wake any terminal unit process waiting in the
+ * dgrp_write routine for low water.
+ */
+
+ if (n > TBUF_LOW)
+ continue;
+
+ if ((ch->ch_flag & CH_LOW) != 0) {
+ ch->ch_flag &= ~CH_LOW;
+ wake_up_interruptible(&ch->ch_flag_wait);
+ }
+
+ /* selwakeup tty_sel */
+ if (ch->ch_tun.un_open_count) {
+ struct tty_struct *tty = (ch->ch_tun.un_tty);
+
+ if (waitqueue_active(&tty->write_wait))
+ wake_up_interruptible(&tty->write_wait);
+
+ tty_wakeup(tty);
+ }
+
+ if (ch->ch_pun.un_open_count) {
+ struct tty_struct *tty = (ch->ch_pun.un_tty);
+
+ if (waitqueue_active(&tty->write_wait))
+ wake_up_interruptible(&tty->write_wait);
+
+ tty_wakeup(tty);
+ }
+
+ /*
+ * Do EMPTY processing.
+ */
+
+ if (n != 0)
+ continue;
+
+ if ((ch->ch_flag & (CH_EMPTY | CH_DRAIN)) != 0 ||
+ (ch->ch_pun.un_flag & UN_EMPTY) != 0) {
+ /*
+ * If there is still data in the server, ask the server
+ * to notify us when its all gone.
+ */
+
+ if (ch->ch_s_treq != ch->ch_s_tin) {
+ b = set_cmd_header(b, port, 43);
+
+ ch->ch_s_treq = ch->ch_s_tin;
+ put_unaligned_be16(ch->ch_s_treq,
+ b);
+ b += 2;
+ }
+
+ /*
+ * If there is a thread waiting for buffer empty,
+ * and we are truly empty, wake the thread.
+ */
+
+ else if ((ch->ch_flag & CH_EMPTY) != 0 &&
+ (ch->ch_send & RR_TX_BREAK) == 0) {
+ ch->ch_flag &= ~CH_EMPTY;
+
+ wake_up_interruptible(&ch->ch_flag_wait);
+ }
+ }
+ }
+
+ /*
+ * If a module select code is needed, drop one in. If space
+ * was reserved for one, but none is needed, recover the space.
+ */
+
+ if (mod != nd->nd_tx_module) {
+ if (b != mbuf) {
+ mbuf[-1] = 0xf0 | mod;
+ nd->nd_tx_module = mod;
+ } else {
+ b--;
+ }
+ }
+ }
+
+ /*
+ * Send a synchronization sequence associated with the last open
+ * channel that sent data, and remember the time when the data was
+ * sent.
+ */
+
+ in = nd->nd_seq_in;
+
+ if ((send_sync || nd->nd_seq_wait[in] != 0) && lastport >= 0) {
+ u8 *bb = b;
+
+ /*
+ * Attempt the use the port that really wanted the sync.
+ * This gets around a race condition where the "lastport" is in
+ * the middle of the close() routine, and by the time we
+ * send this command, it will have already acked the close, and
+ * thus not send the sync response.
+ */
+ if (wanted_sync_port >= 0)
+ lastport = wanted_sync_port;
+ /*
+ * Set a flag just in case the port is in the middle of a close,
+ * it will not be permitted to actually close until we get an
+ * sync response, and clear the flag there.
+ */
+ ch = nd->nd_chan + lastport;
+ ch->ch_flag |= CH_WAITING_SYNC;
+
+ mod = lastport >> 4;
+
+ if (mod != nd->nd_tx_module) {
+ bb[0] = 0xf0 + mod;
+ bb += 1;
+
+ nd->nd_tx_module = mod;
+ }
+
+ bb = set_cmd_header(bb, lastport, 12);
+ *bb++ = in;
+
+ nd->nd_seq_size[in] = bb - buf;
+ nd->nd_seq_time[in] = jiffies;
+
+ if (++in >= SEQ_MAX)
+ in = 0;
+
+ if (in != nd->nd_seq_out) {
+ b = bb;
+ nd->nd_seq_in = in;
+ nd->nd_unack += b - buf;
+ }
+ }
+
+ /*
+ * If there are no open ports, a sync cannot be sent.
+ * There is nothing left to wait for anyway, so wake any
+ * thread waiting for an acknowledgement.
+ */
+
+ else if (nd->nd_seq_wait[in] != 0) {
+ nd->nd_seq_wait[in] = 0;
+
+ wake_up_interruptible(&nd->nd_seq_wque[in]);
+ }
+
+ /*
+ * If there is no traffic for an interval of IDLE_MAX, then
+ * send a single byte packet.
+ */
+
+ if (b != buf) {
+ nd->nd_tx_time = jiffies;
+ } else if ((ulong)(jiffies - nd->nd_tx_time) >= IDLE_MAX) {
+ *b++ = 0xf0 | nd->nd_tx_module;
+ nd->nd_tx_time = jiffies;
+ }
+
+ n = b - buf;
+
+ if (n >= tsafe)
+ pr_info("%s - n(%i) >= tsafe(%i)\n",
+ __func__, n, tsafe);
+
+ if (tsend < 0)
+ dgrp_dump(buf, n);
+
+ nd->nd_tx_work = work;
+
+ return n;
+}
+
+/*
+ * dgrp_net_read()
+ * Data to be sent TO the PortServer from the "async." half of the driver.
+ */
+static ssize_t dgrp_net_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct nd_struct *nd;
+ long n;
+ u8 *local_buf;
+ u8 *b;
+ ssize_t rtn;
+
+ /*
+ * Get the node pointer, and quit if it doesn't exist.
+ */
+ nd = (struct nd_struct *)(file->private_data);
+ if (!nd)
+ return -ENXIO;
+
+ if (count < UIO_MIN)
+ return -EINVAL;
+
+ /*
+ * Only one read/write operation may be in progress at
+ * any given time.
+ */
+
+ /*
+ * Grab the NET lock.
+ */
+ down(&nd->nd_net_semaphore);
+
+ nd->nd_read_count++;
+
+ nd->nd_tx_ready = 0;
+
+ /*
+ * Determine the effective size of the buffer.
+ */
+
+ if (nd->nd_remain > UIO_BASE)
+ pr_info_ratelimited("%s - nd_remain(%i) > UIO_BASE\n",
+ __func__, nd->nd_remain);
+
+ b = local_buf = nd->nd_iobuf + UIO_BASE;
+
+ /*
+ * Generate data according to the node state.
+ */
+
+ switch (nd->nd_state) {
+ /*
+ * Initialize the connection.
+ */
+
+ case NS_IDLE:
+ if (nd->nd_mon_buf)
+ dgrp_monitor_reset(nd);
+
+ /*
+ * Request a Product ID Packet.
+ */
+
+ b[0] = 0xfb;
+ b[1] = 0x01;
+ b += 2;
+
+ nd->nd_expect |= NR_IDENT;
+
+ /*
+ * Request a Server Capability ID Response.
+ */
+
+ b[0] = 0xfb;
+ b[1] = 0x02;
+ b += 2;
+
+ nd->nd_expect |= NR_CAPABILITY;
+
+ /*
+ * Request a Server VPD Response.
+ */
+
+ b[0] = 0xfb;
+ b[1] = 0x18;
+ b += 2;
+
+ nd->nd_expect |= NR_VPD;
+
+ nd->nd_state = NS_WAIT_QUERY;
+ break;
+
+ /*
+ * We do serious communication with the server only in
+ * the READY state.
+ */
+
+ case NS_READY:
+ b = dgrp_send(nd, count) + local_buf;
+ break;
+
+ /*
+ * Send off an error after receiving a bogus message
+ * from the server.
+ */
+
+ case NS_SEND_ERROR:
+ n = strlen(nd->nd_error);
+
+ b[0] = 0xff;
+ b[1] = n;
+ memcpy(b + 2, nd->nd_error, n);
+ b += 2 + n;
+
+ dgrp_net_idle(nd);
+ /*
+ * Set the active port count to zero.
+ */
+ dgrp_chan_count(nd, 0);
+ break;
+
+ default:
+ break;
+ }
+
+ n = b - local_buf;
+
+ if (n != 0) {
+ nd->nd_send_count++;
+
+ nd->nd_tx_byte += n + nd->nd_link.lk_header_size;
+ nd->nd_tx_charge += n + nd->nd_link.lk_header_size;
+ }
+
+ rtn = copy_to_user((void __user *)buf, local_buf, n);
+ if (rtn) {
+ rtn = -EFAULT;
+ goto done;
+ }
+
+ *ppos += n;
+
+ rtn = n;
+
+ if (nd->nd_mon_buf)
+ dgrp_monitor_data(nd, RPDUMP_CLIENT, local_buf, n);
+
+ /*
+ * Release the NET lock.
+ */
+done:
+ up(&nd->nd_net_semaphore);
+
+ return rtn;
+}
+
+/**
+ * dgrp_receive() -- decode data packets received from the remote PortServer.
+ * @nd: pointer to a node structure
+ */
+static void dgrp_receive(struct nd_struct *nd)
+{
+ struct ch_struct *ch;
+ u8 *buf;
+ u8 *b;
+ u8 *dbuf;
+ char *error;
+ long port;
+ long dlen;
+ long plen;
+ long remain;
+ long n;
+ long mlast;
+ long elast;
+ long mstat;
+ long estat;
+
+ char ID[3];
+
+ nd->nd_tx_time = jiffies;
+
+ ID_TO_CHAR(nd->nd_ID, ID);
+
+ b = buf = nd->nd_iobuf;
+ remain = nd->nd_remain;
+
+ /*
+ * Loop to process Realport protocol packets.
+ */
+
+ while (remain > 0) {
+ int n0 = b[0] >> 4;
+ int n1 = b[0] & 0x0f;
+
+ if (n0 <= 12) {
+ port = (nd->nd_rx_module << 4) + n1;
+
+ if (port >= nd->nd_chan_count) {
+ error = "Improper Port Number";
+ goto prot_error;
+ }
+
+ ch = nd->nd_chan + port;
+ } else {
+ port = -1;
+ ch = NULL;
+ }
+
+ /*
+ * Process by major packet type.
+ */
+
+ switch (n0) {
+
+ /*
+ * Process 1-byte header data packet.
+ */
+
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ dlen = n0 + 1;
+ plen = dlen + 1;
+
+ dbuf = b + 1;
+ goto data;
+
+ /*
+ * Process 2-byte header data packet.
+ */
+
+ case 8:
+ if (remain < 3)
+ goto done;
+
+ dlen = b[1];
+ plen = dlen + 2;
+
+ dbuf = b + 2;
+ goto data;
+
+ /*
+ * Process 3-byte header data packet.
+ */
+
+ case 9:
+ if (remain < 4)
+ goto done;
+
+ dlen = get_unaligned_be16(b + 1);
+ plen = dlen + 3;
+
+ dbuf = b + 3;
+
+ /*
+ * Common packet handling code.
+ */
+
+data:
+ nd->nd_tx_work = 1;
+
+ /*
+ * Otherwise data should appear only when we are
+ * in the CS_READY state.
+ */
+
+ if (ch->ch_state < CS_READY) {
+ error = "Data received before RWIN established";
+ goto prot_error;
+ }
+
+ /*
+ * Assure that the data received is within the
+ * allowable window.
+ */
+
+ n = (ch->ch_s_rwin - ch->ch_s_rin) & 0xffff;
+
+ if (dlen > n) {
+ error = "Receive data overrun";
+ goto prot_error;
+ }
+
+ /*
+ * If we received 3 or less characters,
+ * assume it is a human typing, and set RTIME
+ * to 10 milliseconds.
+ *
+ * If we receive 10 or more characters,
+ * assume its not a human typing, and set RTIME
+ * to 100 milliseconds.
+ */
+
+ if (ch->ch_edelay != DGRP_RTIME) {
+ if (ch->ch_rtime != ch->ch_edelay) {
+ ch->ch_rtime = ch->ch_edelay;
+ ch->ch_flag |= CH_PARAM;
+ }
+ } else if (dlen <= 3) {
+ if (ch->ch_rtime != 10) {
+ ch->ch_rtime = 10;
+ ch->ch_flag |= CH_PARAM;
+ }
+ } else {
+ if (ch->ch_rtime != DGRP_RTIME) {
+ ch->ch_rtime = DGRP_RTIME;
+ ch->ch_flag |= CH_PARAM;
+ }
+ }
+
+ /*
+ * If a portion of the packet is outside the
+ * buffer, shorten the effective length of the
+ * data packet to be the amount of data received.
+ */
+
+ if (remain < plen)
+ dlen -= plen - remain;
+
+ /*
+ * Detect if receive flush is now complete.
+ */
+
+ if ((ch->ch_flag & CH_RX_FLUSH) != 0 &&
+ ((ch->ch_flush_seq - nd->nd_seq_out) & SEQ_MASK) >=
+ ((nd->nd_seq_in - nd->nd_seq_out) & SEQ_MASK)) {
+ ch->ch_flag &= ~CH_RX_FLUSH;
+ }
+
+ /*
+ * If we are ready to receive, move the data into
+ * the receive buffer.
+ */
+
+ ch->ch_s_rin = (ch->ch_s_rin + dlen) & 0xffff;
+
+ if (ch->ch_state == CS_READY &&
+ (ch->ch_tun.un_open_count != 0) &&
+ (ch->ch_tun.un_flag & UN_CLOSING) == 0 &&
+ (ch->ch_cflag & CF_CREAD) != 0 &&
+ (ch->ch_flag & (CH_BAUD0 | CH_RX_FLUSH)) == 0 &&
+ (ch->ch_send & RR_RX_FLUSH) == 0) {
+
+ if (ch->ch_rin + dlen >= RBUF_MAX) {
+ n = RBUF_MAX - ch->ch_rin;
+
+ memcpy(ch->ch_rbuf + ch->ch_rin, dbuf, n);
+
+ ch->ch_rin = 0;
+ dbuf += n;
+ dlen -= n;
+ }
+
+ memcpy(ch->ch_rbuf + ch->ch_rin, dbuf, dlen);
+
+ ch->ch_rin += dlen;
+
+
+ /*
+ * If we are not in fastcook mode, or
+ * if there is a fastcook thread
+ * waiting for data, send the data to
+ * the line discipline.
+ */
+
+ if ((ch->ch_flag & CH_FAST_READ) == 0 ||
+ ch->ch_inwait != 0) {
+ dgrp_input(ch);
+ }
+
+ /*
+ * If there is a read thread waiting
+ * in select, and we are in fastcook
+ * mode, wake him up.
+ */
+
+ if (waitqueue_active(&ch->ch_tun.un_tty->read_wait) &&
+ (ch->ch_flag & CH_FAST_READ) != 0)
+ wake_up_interruptible(&ch->ch_tun.un_tty->read_wait);
+
+ /*
+ * Wake any thread waiting in the
+ * fastcook loop.
+ */
+
+ if ((ch->ch_flag & CH_INPUT) != 0) {
+ ch->ch_flag &= ~CH_INPUT;
+
+ wake_up_interruptible(&ch->ch_flag_wait);
+ }
+ }
+
+ /*
+ * Fabricate and insert a data packet header to
+ * preceed the remaining data when it comes in.
+ */
+
+ if (remain < plen) {
+ dlen = plen - remain;
+ b = buf;
+
+ b[0] = 0x90 + n1;
+ put_unaligned_be16(dlen, b + 1);
+
+ remain = 3;
+ goto done;
+ }
+ break;
+
+ /*
+ * Handle Window Sequence packets.
+ */
+
+ case 10:
+ plen = 3;
+ if (remain < plen)
+ goto done;
+
+ nd->nd_tx_work = 1;
+
+ {
+ ushort tpos = get_unaligned_be16(b + 1);
+
+ ushort ack = (tpos - ch->ch_s_tpos) & 0xffff;
+ ushort unack = (ch->ch_s_tin - ch->ch_s_tpos) & 0xffff;
+ ushort notify = (ch->ch_s_treq - ch->ch_s_tpos) & 0xffff;
+
+ if (ch->ch_state < CS_READY || ack > unack) {
+ error = "Improper Window Sequence";
+ goto prot_error;
+ }
+
+ ch->ch_s_tpos = tpos;
+
+ if (notify <= ack)
+ ch->ch_s_treq = tpos;
+ }
+ break;
+
+ /*
+ * Handle Command response packets.
+ */
+
+ case 11:
+
+ /*
+ * RealPort engine fix - 03/11/2004
+ *
+ * This check did not used to be here.
+ *
+ * We were using b[1] without verifying that the data
+ * is actually there and valid. On a split packet, it
+ * might not be yet.
+ *
+ * NOTE: I have never actually seen the failure happen
+ * under Linux, but since I have seen it occur
+ * under both Solaris and HP-UX, the assumption
+ * is that it *could* happen here as well...
+ */
+ if (remain < 2)
+ goto done;
+
+
+ switch (b[1]) {
+
+ /*
+ * Handle Open Response.
+ */
+
+ case 11:
+ plen = 6;
+ if (remain < plen)
+ goto done;
+
+ nd->nd_tx_work = 1;
+
+ {
+ int req = b[2];
+ int resp = b[3];
+ port = get_unaligned_be16(b + 4);
+
+ if (port >= nd->nd_chan_count) {
+ error = "Open channel number out of range";
+ goto prot_error;
+ }
+
+ ch = nd->nd_chan + port;
+
+ /*
+ * How we handle an open response depends primarily
+ * on our current channel state.
+ */
+
+ switch (ch->ch_state) {
+ case CS_IDLE:
+
+ /*
+ * Handle a delayed open.
+ */
+
+ if (ch->ch_otype_waiting != 0 &&
+ req == ch->ch_otype_waiting &&
+ resp == 0) {
+ ch->ch_otype = req;
+ ch->ch_otype_waiting = 0;
+ ch->ch_state = CS_SEND_QUERY;
+ break;
+ }
+ goto open_error;
+
+ case CS_WAIT_OPEN:
+
+ /*
+ * Handle the open response.
+ */
+
+ if (req == ch->ch_otype) {
+ switch (resp) {
+
+ /*
+ * On successful response, open the
+ * port and proceed normally.
+ */
+
+ case 0:
+ ch->ch_state = CS_SEND_QUERY;
+ break;
+
+ /*
+ * On a busy response to a persistent open,
+ * remember that the open is pending.
+ */
+
+ case 1:
+ case 2:
+ if (req != OTYPE_IMMEDIATE) {
+ ch->ch_otype_waiting = req;
+ ch->ch_state = CS_IDLE;
+ break;
+ }
+
+ /*
+ * Otherwise the server open failed. If
+ * the Unix port is open, hang it up.
+ */
+
+ default:
+ if (ch->ch_open_count != 0) {
+ ch->ch_flag |= CH_HANGUP;
+ dgrp_carrier(ch);
+ ch->ch_state = CS_IDLE;
+ break;
+ }
+
+ ch->ch_open_error = resp;
+ ch->ch_state = CS_IDLE;
+
+ wake_up_interruptible(&ch->ch_flag_wait);
+ }
+ break;
+ }
+
+ /*
+ * Handle delayed response arrival preceeding
+ * the open response we are waiting for.
+ */
+
+ if (ch->ch_otype_waiting != 0 &&
+ req == ch->ch_otype_waiting &&
+ resp == 0) {
+ ch->ch_otype = ch->ch_otype_waiting;
+ ch->ch_otype_waiting = 0;
+ ch->ch_state = CS_WAIT_FAIL;
+ break;
+ }
+ goto open_error;
+
+
+ case CS_WAIT_FAIL:
+
+ /*
+ * Handle response to immediate open arriving
+ * after a delayed open success.
+ */
+
+ if (req == OTYPE_IMMEDIATE) {
+ ch->ch_state = CS_SEND_QUERY;
+ break;
+ }
+ goto open_error;
+
+
+ case CS_WAIT_CANCEL:
+ /*
+ * Handle delayed open response arriving before
+ * the cancel response.
+ */
+
+ if (req == ch->ch_otype_waiting &&
+ resp == 0) {
+ ch->ch_otype_waiting = 0;
+ break;
+ }
+
+ /*
+ * Handle cancel response.
+ */
+
+ if (req == 4 && resp == 0) {
+ ch->ch_otype_waiting = 0;
+ ch->ch_state = CS_IDLE;
+ break;
+ }
+ goto open_error;
+
+
+ case CS_WAIT_CLOSE:
+ /*
+ * Handle a successful response to a port
+ * close.
+ */
+
+ if (req >= 3) {
+ ch->ch_state = CS_IDLE;
+ break;
+ }
+ goto open_error;
+
+open_error:
+ default:
+ {
+ error = "Improper Open Response";
+ goto prot_error;
+ }
+ }
+ }
+ break;
+
+ /*
+ * Handle Synchronize Response.
+ */
+
+ case 13:
+ plen = 3;
+ if (remain < plen)
+ goto done;
+ {
+ int seq = b[2];
+ int s;
+
+ /*
+ * If channel was waiting for this sync response,
+ * unset the flag, and wake up anyone waiting
+ * on the event.
+ */
+ if (ch->ch_flag & CH_WAITING_SYNC) {
+ ch->ch_flag &= ~(CH_WAITING_SYNC);
+ wake_up_interruptible(&ch->ch_flag_wait);
+ }
+
+ if (((seq - nd->nd_seq_out) & SEQ_MASK) >=
+ ((nd->nd_seq_in - nd->nd_seq_out) & SEQ_MASK)) {
+ break;
+ }
+
+ for (s = nd->nd_seq_out;; s = (s + 1) & SEQ_MASK) {
+ if (nd->nd_seq_wait[s] != 0) {
+ nd->nd_seq_wait[s] = 0;
+
+ wake_up_interruptible(&nd->nd_seq_wque[s]);
+ }
+
+ nd->nd_unack -= nd->nd_seq_size[s];
+
+ if (s == seq)
+ break;
+ }
+
+ nd->nd_seq_out = (seq + 1) & SEQ_MASK;
+ }
+ break;
+
+ /*
+ * Handle Sequence Response.
+ */
+
+ case 15:
+ plen = 6;
+ if (remain < plen)
+ goto done;
+
+ {
+ /* Record that we have received the Sequence
+ * Response, but we aren't interested in the
+ * sequence numbers. We were using RIN like it
+ * was ROUT and that was causing problems,
+ * fixed 7-13-2001 David Fries. See comment in
+ * drp.h for ch_s_rin variable.
+ int rin = get_unaligned_be16(b + 2);
+ int tpos = get_unaligned_be16(b + 4);
+ */
+
+ ch->ch_send &= ~RR_SEQUENCE;
+ ch->ch_expect &= ~RR_SEQUENCE;
+ }
+ goto check_query;
+
+ /*
+ * Handle Status Response.
+ */
+
+ case 17:
+ plen = 5;
+ if (remain < plen)
+ goto done;
+
+ {
+ ch->ch_s_elast = get_unaligned_be16(b + 2);
+ ch->ch_s_mlast = b[4];
+
+ ch->ch_expect &= ~RR_STATUS;
+ ch->ch_send &= ~RR_STATUS;
+
+ /*
+ * CH_PHYS_CD is cleared because something _could_ be
+ * waiting for the initial sense of carrier... and if
+ * carrier is high immediately, we want to be sure to
+ * wake them as soon as possible.
+ */
+ ch->ch_flag &= ~CH_PHYS_CD;
+
+ dgrp_carrier(ch);
+ }
+ goto check_query;
+
+ /*
+ * Handle Line Error Response.
+ */
+
+ case 19:
+ plen = 14;
+ if (remain < plen)
+ goto done;
+
+ break;
+
+ /*
+ * Handle Buffer Response.
+ */
+
+ case 21:
+ plen = 6;
+ if (remain < plen)
+ goto done;
+
+ {
+ ch->ch_s_rsize = get_unaligned_be16(b + 2);
+ ch->ch_s_tsize = get_unaligned_be16(b + 4);
+
+ ch->ch_send &= ~RR_BUFFER;
+ ch->ch_expect &= ~RR_BUFFER;
+ }
+ goto check_query;
+
+ /*
+ * Handle Port Capability Response.
+ */
+
+ case 23:
+ plen = 32;
+ if (remain < plen)
+ goto done;
+
+ {
+ ch->ch_send &= ~RR_CAPABILITY;
+ ch->ch_expect &= ~RR_CAPABILITY;
+ }
+
+ /*
+ * When all queries are complete, set those parameters
+ * derived from the query results, then transition
+ * to the READY state.
+ */
+
+check_query:
+ if (ch->ch_state == CS_WAIT_QUERY &&
+ (ch->ch_expect & (RR_SEQUENCE |
+ RR_STATUS |
+ RR_BUFFER |
+ RR_CAPABILITY)) == 0) {
+ ch->ch_tmax = ch->ch_s_tsize / 4;
+
+ if (ch->ch_edelay == DGRP_TTIME)
+ ch->ch_ttime = DGRP_TTIME;
+ else
+ ch->ch_ttime = ch->ch_edelay;
+
+ ch->ch_rmax = ch->ch_s_rsize / 4;
+
+ if (ch->ch_edelay == DGRP_RTIME)
+ ch->ch_rtime = DGRP_RTIME;
+ else
+ ch->ch_rtime = ch->ch_edelay;
+
+ ch->ch_rlow = 2 * ch->ch_s_rsize / 8;
+ ch->ch_rhigh = 6 * ch->ch_s_rsize / 8;
+
+ ch->ch_state = CS_READY;
+
+ nd->nd_tx_work = 1;
+ wake_up_interruptible(&ch->ch_flag_wait);
+
+ }
+ break;
+
+ default:
+ goto decode_error;
+ }
+ break;
+
+ /*
+ * Handle Events.
+ */
+
+ case 12:
+ plen = 4;
+ if (remain < plen)
+ goto done;
+
+ mlast = ch->ch_s_mlast;
+ elast = ch->ch_s_elast;
+
+ mstat = ch->ch_s_mlast = b[1];
+ estat = ch->ch_s_elast = get_unaligned_be16(b + 2);
+
+ /*
+ * Handle modem changes.
+ */
+
+ if (((mstat ^ mlast) & DM_CD) != 0)
+ dgrp_carrier(ch);
+
+
+ /*
+ * Handle received break.
+ */
+
+ if ((estat & ~elast & EV_RXB) != 0 &&
+ (ch->ch_tun.un_open_count != 0) &&
+ I_BRKINT(ch->ch_tun.un_tty) &&
+ !(I_IGNBRK(ch->ch_tun.un_tty))) {
+
+ tty_buffer_request_room(ch->ch_tun.un_tty, 1);
+ tty_insert_flip_char(ch->ch_tun.un_tty, 0, TTY_BREAK);
+ tty_flip_buffer_push(ch->ch_tun.un_tty);
+
+ }
+
+ /*
+ * On transmit break complete, if more break traffic
+ * is waiting then send it. Otherwise wake any threads
+ * waiting for transmitter empty.
+ */
+
+ if ((~estat & elast & EV_TXB) != 0 &&
+ (ch->ch_expect & RR_TX_BREAK) != 0) {
+
+ nd->nd_tx_work = 1;
+
+ ch->ch_expect &= ~RR_TX_BREAK;
+
+ if (ch->ch_break_time != 0) {
+ ch->ch_send |= RR_TX_BREAK;
+ } else {
+ ch->ch_send &= ~RR_TX_BREAK;
+ ch->ch_flag &= ~CH_TX_BREAK;
+ wake_up_interruptible(&ch->ch_flag_wait);
+ }
+ }
+ break;
+
+ case 13:
+ case 14:
+ error = "Unrecognized command";
+ goto prot_error;
+
+ /*
+ * Decode Special Codes.
+ */
+
+ case 15:
+ switch (n1) {
+ /*
+ * One byte module select.
+ */
+
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ plen = 1;
+ nd->nd_rx_module = n1;
+ break;
+
+ /*
+ * Two byte module select.
+ */
+
+ case 8:
+ plen = 2;
+ if (remain < plen)
+ goto done;
+
+ nd->nd_rx_module = b[1];
+ break;
+
+ /*
+ * ID Request packet.
+ */
+
+ case 11:
+ if (remain < 4)
+ goto done;
+
+ plen = get_unaligned_be16(b + 2);
+
+ if (plen < 12 || plen > 1000) {
+ error = "Response Packet length error";
+ goto prot_error;
+ }
+
+ nd->nd_tx_work = 1;
+
+ switch (b[1]) {
+ /*
+ * Echo packet.
+ */
+
+ case 0:
+ nd->nd_send |= NR_ECHO;
+ break;
+
+ /*
+ * ID Response packet.
+ */
+
+ case 1:
+ nd->nd_send |= NR_IDENT;
+ break;
+
+ /*
+ * ID Response packet.
+ */
+
+ case 32:
+ nd->nd_send |= NR_PASSWORD;
+ break;
+
+ }
+ break;
+
+ /*
+ * Various node-level response packets.
+ */
+
+ case 12:
+ if (remain < 4)
+ goto done;
+
+ plen = get_unaligned_be16(b + 2);
+
+ if (plen < 4 || plen > 1000) {
+ error = "Response Packet length error";
+ goto prot_error;
+ }
+
+ nd->nd_tx_work = 1;
+
+ switch (b[1]) {
+ /*
+ * Echo packet.
+ */
+
+ case 0:
+ nd->nd_expect &= ~NR_ECHO;
+ break;
+
+ /*
+ * Product Response Packet.
+ */
+
+ case 1:
+ {
+ int desclen;
+
+ nd->nd_hw_ver = (b[8] << 8) | b[9];
+ nd->nd_sw_ver = (b[10] << 8) | b[11];
+ nd->nd_hw_id = b[6];
+ desclen = ((plen - 12) > MAX_DESC_LEN) ? MAX_DESC_LEN :
+ plen - 12;
+
+ if (desclen <= 0) {
+ error = "Response Packet desclen error";
+ goto prot_error;
+ }
+
+ strncpy(nd->nd_ps_desc, b + 12, desclen);
+ nd->nd_ps_desc[desclen] = 0;
+ }
+
+ nd->nd_expect &= ~NR_IDENT;
+ break;
+
+ /*
+ * Capability Response Packet.
+ */
+
+ case 2:
+ {
+ int nn = get_unaligned_be16(b + 4);
+
+ if (nn > CHAN_MAX)
+ nn = CHAN_MAX;
+
+ dgrp_chan_count(nd, nn);
+ }
+
+ nd->nd_expect &= ~NR_CAPABILITY;
+ break;
+
+ /*
+ * VPD Response Packet.
+ */
+
+ case 15:
+ /*
+ * NOTE: case 15 is here ONLY because the EtherLite
+ * is broken, and sends a response to 24 back as 15.
+ * To resolve this, the EtherLite firmware is now
+ * fixed to send back 24 correctly, but, for backwards
+ * compatibility, we now have reserved 15 for the
+ * bad EtherLite response to 24 as well.
+ */
+
+ /* Fallthru! */
+
+ case 24:
+
+ /*
+ * If the product doesn't support VPD,
+ * it will send back a null IDRESP,
+ * which is a length of 4 bytes.
+ */
+ if (plen > 4) {
+ memcpy(nd->nd_vpd, b + 4, min(plen - 4, (long) VPDSIZE));
+ nd->nd_vpd_len = min(plen - 4, (long) VPDSIZE);
+ }
+
+ nd->nd_expect &= ~NR_VPD;
+ break;
+
+ default:
+ goto decode_error;
+ }
+
+ if (nd->nd_expect == 0 &&
+ nd->nd_state == NS_WAIT_QUERY) {
+ nd->nd_state = NS_READY;
+ }
+ break;
+
+ /*
+ * Debug packet.
+ */
+
+ case 14:
+ if (remain < 4)
+ goto done;
+
+ plen = get_unaligned_be16(b + 2) + 4;
+
+ if (plen > 1000) {
+ error = "Debug Packet too large";
+ goto prot_error;
+ }
+
+ if (remain < plen)
+ goto done;
+ break;
+
+ /*
+ * Handle reset packet.
+ */
+
+ case 15:
+ if (remain < 2)
+ goto done;
+
+ plen = 2 + b[1];
+
+ if (remain < plen)
+ goto done;
+
+ nd->nd_tx_work = 1;
+
+ n = b[plen];
+ b[plen] = 0;
+
+ b[plen] = n;
+
+ error = "Client Reset Acknowledge";
+ goto prot_error;
+
+ default:
+ goto decode_error;
+ }
+ break;
+
+ default:
+ goto decode_error;
+ }
+
+ b += plen;
+ remain -= plen;
+ }
+
+ /*
+ * When the buffer is exhausted, copy any data left at the
+ * top of the buffer back down to the bottom for the next
+ * read request.
+ */
+
+done:
+ if (remain > 0 && b != buf)
+ memcpy(buf, b, remain);
+
+ nd->nd_remain = remain;
+ return;
+
+/*
+ * Handle a decode error.
+ */
+
+decode_error:
+ error = "Protocol decode error";
+
+/*
+ * Handle a general protocol error.
+ */
+
+prot_error:
+ nd->nd_remain = 0;
+ nd->nd_state = NS_SEND_ERROR;
+ nd->nd_error = error;
+}
+
+/*
+ * dgrp_net_write() -- write data to the network device.
+ *
+ * A zero byte write indicates that the connection to the RealPort
+ * device has been broken.
+ *
+ * A non-zero write indicates data from the RealPort device.
+ */
+static ssize_t dgrp_net_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct nd_struct *nd;
+ ssize_t rtn = 0;
+ long n;
+ long total = 0;
+
+ /*
+ * Get the node pointer, and quit if it doesn't exist.
+ */
+ nd = (struct nd_struct *)(file->private_data);
+ if (!nd)
+ return -ENXIO;
+
+ /*
+ * Grab the NET lock.
+ */
+ down(&nd->nd_net_semaphore);
+
+ nd->nd_write_count++;
+
+ /*
+ * Handle disconnect.
+ */
+
+ if (count == 0) {
+ dgrp_net_idle(nd);
+ /*
+ * Set the active port count to zero.
+ */
+ dgrp_chan_count(nd, 0);
+ goto unlock;
+ }
+
+ /*
+ * Loop to process entire receive packet.
+ */
+
+ while (count > 0) {
+ n = UIO_MAX - nd->nd_remain;
+
+ if (n > count)
+ n = count;
+
+ nd->nd_rx_byte += n + nd->nd_link.lk_header_size;
+
+ rtn = copy_from_user(nd->nd_iobuf + nd->nd_remain,
+ (void __user *) buf + total, n);
+ if (rtn) {
+ rtn = -EFAULT;
+ goto unlock;
+ }
+
+ *ppos += n;
+
+ total += n;
+
+ count -= n;
+
+ if (nd->nd_mon_buf)
+ dgrp_monitor_data(nd, RPDUMP_SERVER,
+ nd->nd_iobuf + nd->nd_remain, n);
+
+ nd->nd_remain += n;
+
+ dgrp_receive(nd);
+ }
+
+ rtn = total;
+
+unlock:
+ /*
+ * Release the NET lock.
+ */
+ up(&nd->nd_net_semaphore);
+
+ return rtn;
+}
+
+
+/*
+ * dgrp_net_select()
+ * Determine whether a device is ready to be read or written to, and
+ * sleep if not.
+ */
+static unsigned int dgrp_net_select(struct file *file,
+ struct poll_table_struct *table)
+{
+ unsigned int retval = 0;
+ struct nd_struct *nd = file->private_data;
+
+ poll_wait(file, &nd->nd_tx_waitq, table);
+
+ if (nd->nd_tx_ready)
+ retval |= POLLIN | POLLRDNORM; /* Conditionally readable */
+
+ retval |= POLLOUT | POLLWRNORM; /* Always writeable */
+
+ return retval;
+}
+
+/*
+ * dgrp_net_ioctl
+ *
+ * Implement those functions which allow the network daemon to control
+ * the network parameters in the driver. The ioctls include ones to
+ * get and set the link speed parameters for the PortServer.
+ */
+static long dgrp_net_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct nd_struct *nd;
+ int rtn = 0;
+ long size = _IOC_SIZE(cmd);
+ struct link_struct link;
+
+ nd = file->private_data;
+
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ rtn = access_ok(VERIFY_WRITE, (void __user *) arg, size);
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ rtn = access_ok(VERIFY_READ, (void __user *) arg, size);
+
+ if (!rtn)
+ return rtn;
+
+ switch (cmd) {
+ case DIGI_SETLINK:
+ if (size != sizeof(struct link_struct))
+ return -EINVAL;
+
+ if (copy_from_user((void *)(&link), (void __user *) arg, size))
+ return -EFAULT;
+
+ if (link.lk_fast_rate < 9600)
+ link.lk_fast_rate = 9600;
+
+ if (link.lk_slow_rate < 2400)
+ link.lk_slow_rate = 2400;
+
+ if (link.lk_fast_rate > 10000000)
+ link.lk_fast_rate = 10000000;
+
+ if (link.lk_slow_rate > link.lk_fast_rate)
+ link.lk_slow_rate = link.lk_fast_rate;
+
+ if (link.lk_fast_delay > 2000)
+ link.lk_fast_delay = 2000;
+
+ if (link.lk_slow_delay > 10000)
+ link.lk_slow_delay = 10000;
+
+ if (link.lk_fast_delay < 60)
+ link.lk_fast_delay = 60;
+
+ if (link.lk_slow_delay < link.lk_fast_delay)
+ link.lk_slow_delay = link.lk_fast_delay;
+
+ if (link.lk_header_size < 2)
+ link.lk_header_size = 2;
+
+ if (link.lk_header_size > 128)
+ link.lk_header_size = 128;
+
+ link.lk_fast_rate /= 8 * 1000 / dgrp_poll_tick;
+ link.lk_slow_rate /= 8 * 1000 / dgrp_poll_tick;
+
+ link.lk_fast_delay /= dgrp_poll_tick;
+ link.lk_slow_delay /= dgrp_poll_tick;
+
+ nd->nd_link = link;
+
+ break;
+
+ case DIGI_GETLINK:
+ if (size != sizeof(struct link_struct))
+ return -EINVAL;
+
+ if (copy_to_user((void __user *)arg, (void *)(&nd->nd_link),
+ size))
+ return -EFAULT;
+
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+
+ return 0;
+}
+
+/**
+ * dgrp_poll_handler() -- handler for poll timer
+ *
+ * As each timer expires, it determines (a) whether the "transmit"
+ * waiter needs to be woken up, and (b) whether the poller needs to
+ * be rescheduled.
+ */
+void dgrp_poll_handler(unsigned long arg)
+{
+ struct dgrp_poll_data *poll_data;
+ struct nd_struct *nd;
+ struct link_struct *lk;
+ ulong time;
+ ulong poll_time;
+ ulong freq;
+ ulong lock_flags;
+
+ poll_data = (struct dgrp_poll_data *) arg;
+ freq = 1000 / poll_data->poll_tick;
+ poll_data->poll_round += 17;
+
+ if (poll_data->poll_round >= freq)
+ poll_data->poll_round -= freq;
+
+ /*
+ * Loop to process all open nodes.
+ *
+ * For each node, determine the rate at which it should
+ * be transmitting data. Then if the node should wake up
+ * and transmit data now, enable the net receive select
+ * to get the transmit going.
+ */
+
+ list_for_each_entry(nd, &nd_struct_list, list) {
+
+ lk = &nd->nd_link;
+
+ /*
+ * Decrement statistics. These are only for use with
+ * KME, so don't worry that the operations are done
+ * unlocked, and so the results are occassionally wrong.
+ */
+
+ nd->nd_read_count -= (nd->nd_read_count +
+ poll_data->poll_round) / freq;
+ nd->nd_write_count -= (nd->nd_write_count +
+ poll_data->poll_round) / freq;
+ nd->nd_send_count -= (nd->nd_send_count +
+ poll_data->poll_round) / freq;
+ nd->nd_tx_byte -= (nd->nd_tx_byte +
+ poll_data->poll_round) / freq;
+ nd->nd_rx_byte -= (nd->nd_rx_byte +
+ poll_data->poll_round) / freq;
+
+ /*
+ * Wake the daemon to transmit data only when there is
+ * enough byte credit to send data.
+ *
+ * The results are approximate because the operations
+ * are performed unlocked, and we are inspecting
+ * data asynchronously updated elsewhere. The whole
+ * thing is just approximation anyway, so that should
+ * be okay.
+ */
+
+ if (lk->lk_slow_rate >= UIO_MAX) {
+
+ nd->nd_delay = 0;
+ nd->nd_rate = UIO_MAX;
+
+ nd->nd_tx_deposit = nd->nd_tx_charge + 3 * UIO_MAX;
+ nd->nd_tx_credit = 3 * UIO_MAX;
+
+ } else {
+
+ long rate;
+ long delay;
+ long deposit;
+ long charge;
+ long size;
+ long excess;
+
+ long seq_in = nd->nd_seq_in;
+ long seq_out = nd->nd_seq_out;
+
+ /*
+ * If there are no outstanding packets, run at the
+ * fastest rate.
+ */
+
+ if (seq_in == seq_out) {
+ delay = 0;
+ rate = lk->lk_fast_rate;
+ }
+
+ /*
+ * Otherwise compute the transmit rate based on the
+ * delay since the oldest packet.
+ */
+
+ else {
+ /*
+ * The actual delay is computed as the
+ * time since the oldest unacknowledged
+ * packet was sent, minus the time it
+ * took to send that packet to the server.
+ */
+
+ delay = ((jiffies - nd->nd_seq_time[seq_out])
+ - (nd->nd_seq_size[seq_out] /
+ lk->lk_fast_rate));
+
+ /*
+ * If the delay is less than the "fast"
+ * delay, transmit full speed. If greater
+ * than the "slow" delay, transmit at the
+ * "slow" speed. In between, interpolate
+ * between the fast and slow speeds.
+ */
+
+ rate =
+ (delay <= lk->lk_fast_delay ?
+ lk->lk_fast_rate :
+ delay >= lk->lk_slow_delay ?
+ lk->lk_slow_rate :
+ (lk->lk_slow_rate +
+ (lk->lk_slow_delay - delay) *
+ (lk->lk_fast_rate - lk->lk_slow_rate) /
+ (lk->lk_slow_delay - lk->lk_fast_delay)
+ )
+ );
+ }
+
+ nd->nd_delay = delay;
+ nd->nd_rate = rate;
+
+ /*
+ * Increase the transmit credit by depositing the
+ * current transmit rate.
+ */
+
+ deposit = nd->nd_tx_deposit;
+ charge = nd->nd_tx_charge;
+
+ deposit += rate;
+
+ /*
+ * If the available transmit credit becomes too large,
+ * reduce the deposit to correct the value.
+ *
+ * Too large is the max of:
+ * 6 times the header size
+ * 3 times the current transmit rate.
+ */
+
+ size = 2 * nd->nd_link.lk_header_size;
+
+ if (size < rate)
+ size = rate;
+
+ size *= 3;
+
+ excess = deposit - charge - size;
+
+ if (excess > 0)
+ deposit -= excess;
+
+ nd->nd_tx_deposit = deposit;
+ nd->nd_tx_credit = deposit - charge;
+
+ /*
+ * Wake the transmit task only if the transmit credit
+ * is at least 3 times the transmit header size.
+ */
+
+ size = 3 * lk->lk_header_size;
+
+ if (nd->nd_tx_credit < size)
+ continue;
+ }
+
+
+ /*
+ * Enable the READ select to wake the daemon if there
+ * is useful work for the drp_read routine to perform.
+ */
+
+ if (waitqueue_active(&nd->nd_tx_waitq) &&
+ (nd->nd_tx_work != 0 ||
+ (ulong)(jiffies - nd->nd_tx_time) >= IDLE_MAX)) {
+ nd->nd_tx_ready = 1;
+
+ wake_up_interruptible(&nd->nd_tx_waitq);
+
+ /* not needed */
+ /* nd->nd_flag &= ~ND_SELECT; */
+ }
+ }
+
+
+ /*
+ * Schedule ourself back at the nominal wakeup interval.
+ */
+ spin_lock_irqsave(&poll_data->poll_lock, lock_flags);
+
+ poll_data->node_active_count--;
+ if (poll_data->node_active_count > 0) {
+ poll_data->node_active_count++;
+ poll_time = poll_data->timer.expires +
+ poll_data->poll_tick * HZ / 1000;
+
+ time = poll_time - jiffies;
+
+ if (time >= 2 * poll_data->poll_tick)
+ poll_time = jiffies + dgrp_poll_tick * HZ / 1000;
+
+ poll_data->timer.expires = poll_time;
+ add_timer(&poll_data->timer);
+ }
+
+ spin_unlock_irqrestore(&poll_data->poll_lock, lock_flags);
+}
diff --git a/drivers/staging/dgrp/dgrp_ports_ops.c b/drivers/staging/dgrp/dgrp_ports_ops.c
new file mode 100644
index 000000000000..cd1fc2088624
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_ports_ops.c
@@ -0,0 +1,170 @@
+/*
+ *
+ * Copyright 1999-2000 Digi International (www.digi.com)
+ * James Puzzo <jamesp at digi dot com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ *
+ * Filename:
+ *
+ * dgrp_ports_ops.c
+ *
+ * Description:
+ *
+ * Handle the file operations required for the /proc/dgrp/ports/...
+ * devices. Basically gathers tty status for the node and returns it.
+ *
+ * Author:
+ *
+ * James A. Puzzo
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+
+#include "dgrp_common.h"
+
+/* File operation declarations */
+static int dgrp_ports_open(struct inode *, struct file *);
+
+static const struct file_operations ports_ops = {
+ .owner = THIS_MODULE,
+ .open = dgrp_ports_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release
+};
+
+static struct inode_operations ports_inode_ops = {
+ .permission = dgrp_inode_permission
+};
+
+
+void dgrp_register_ports_hook(struct proc_dir_entry *de)
+{
+ struct nd_struct *node = de->data;
+
+ de->proc_iops = &ports_inode_ops;
+ de->proc_fops = &ports_ops;
+ node->nd_ports_de = de;
+}
+
+static void *dgrp_ports_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ if (*pos == 0)
+ seq_puts(seq, "#num tty_open pr_open tot_wait MSTAT IFLAG OFLAG CFLAG BPS DIGIFLAGS\n");
+
+ return pos;
+}
+
+static void *dgrp_ports_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct nd_struct *nd = seq->private;
+
+ if (*pos >= nd->nd_chan_count)
+ return NULL;
+
+ *pos += 1;
+
+ return pos;
+}
+
+static void dgrp_ports_seq_stop(struct seq_file *seq, void *v)
+{
+}
+
+static int dgrp_ports_seq_show(struct seq_file *seq, void *v)
+{
+ loff_t *pos = v;
+ struct nd_struct *nd;
+ struct ch_struct *ch;
+ struct un_struct *tun, *pun;
+ unsigned int totcnt;
+
+ nd = seq->private;
+ if (!nd)
+ return 0;
+
+ if (*pos >= nd->nd_chan_count)
+ return 0;
+
+ ch = &nd->nd_chan[*pos];
+ tun = &ch->ch_tun;
+ pun = &ch->ch_pun;
+
+ /*
+ * If port is not open and no one is waiting to
+ * open it, the modem signal values can't be
+ * trusted, and will be zeroed.
+ */
+ totcnt = tun->un_open_count +
+ pun->un_open_count +
+ ch->ch_wait_count[0] +
+ ch->ch_wait_count[1] +
+ ch->ch_wait_count[2];
+
+ seq_printf(seq, "%02d %02d %02d %02d 0x%04X 0x%04X 0x%04X 0x%04X %-6d 0x%04X\n",
+ (int) *pos,
+ tun->un_open_count,
+ pun->un_open_count,
+ ch->ch_wait_count[0] +
+ ch->ch_wait_count[1] +
+ ch->ch_wait_count[2],
+ (totcnt ? ch->ch_s_mlast : 0),
+ ch->ch_s_iflag,
+ ch->ch_s_oflag,
+ ch->ch_s_cflag,
+ (ch->ch_s_brate ? (1843200 / ch->ch_s_brate) : 0),
+ ch->ch_digi.digi_flags);
+
+ return 0;
+}
+
+static const struct seq_operations ports_seq_ops = {
+ .start = dgrp_ports_seq_start,
+ .next = dgrp_ports_seq_next,
+ .stop = dgrp_ports_seq_stop,
+ .show = dgrp_ports_seq_show,
+};
+
+/**
+ * dgrp_ports_open -- open the /proc/dgrp/ports/... device
+ * @inode: struct inode *
+ * @file: struct file *
+ *
+ * Open function to open the /proc/dgrp/ports device for a PortServer.
+ * This is the open function for struct file_operations
+ */
+static int dgrp_ports_open(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq;
+ int rtn;
+
+ rtn = seq_open(file, &ports_seq_ops);
+ if (!rtn) {
+ seq = file->private_data;
+ seq->private = PDE(inode)->data;
+ }
+
+ return rtn;
+}
diff --git a/drivers/staging/dgrp/dgrp_specproc.c b/drivers/staging/dgrp/dgrp_specproc.c
new file mode 100644
index 000000000000..28f5c9ab6b43
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_specproc.c
@@ -0,0 +1,822 @@
+/*
+ *
+ * Copyright 1999 Digi International (www.digi.com)
+ * James Puzzo <jamesp at digi dot com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ */
+
+/*
+ *
+ * Filename:
+ *
+ * dgrp_specproc.c
+ *
+ * Description:
+ *
+ * Handle the "config" proc entry for the linux realport device driver
+ * and provide slots for the "net" and "mon" devices
+ *
+ * Author:
+ *
+ * James A. Puzzo
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/cred.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/seq_file.h>
+#include <linux/vmalloc.h>
+
+#include "dgrp_common.h"
+
+static struct dgrp_proc_entry dgrp_table[];
+static struct proc_dir_entry *dgrp_proc_dir_entry;
+
+static int dgrp_add_id(long id);
+static int dgrp_remove_nd(struct nd_struct *nd);
+static void unregister_dgrp_device(struct proc_dir_entry *de);
+static void register_dgrp_device(struct nd_struct *node,
+ struct proc_dir_entry *root,
+ void (*register_hook)(struct proc_dir_entry *de));
+
+/* File operation declarations */
+static int dgrp_gen_proc_open(struct inode *, struct file *);
+static int dgrp_gen_proc_close(struct inode *, struct file *);
+static int parse_write_config(char *);
+
+
+static const struct file_operations dgrp_proc_file_ops = {
+ .owner = THIS_MODULE,
+ .open = dgrp_gen_proc_open,
+ .release = dgrp_gen_proc_close,
+};
+
+static struct inode_operations proc_inode_ops = {
+ .permission = dgrp_inode_permission
+};
+
+
+static void register_proc_table(struct dgrp_proc_entry *,
+ struct proc_dir_entry *);
+static void unregister_proc_table(struct dgrp_proc_entry *,
+ struct proc_dir_entry *);
+
+static struct dgrp_proc_entry dgrp_net_table[];
+static struct dgrp_proc_entry dgrp_mon_table[];
+static struct dgrp_proc_entry dgrp_ports_table[];
+static struct dgrp_proc_entry dgrp_dpa_table[];
+
+static ssize_t config_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *pos);
+
+static int nodeinfo_proc_open(struct inode *inode, struct file *file);
+static int info_proc_open(struct inode *inode, struct file *file);
+static int config_proc_open(struct inode *inode, struct file *file);
+
+static struct file_operations config_proc_file_ops = {
+ .owner = THIS_MODULE,
+ .open = config_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+ .write = config_proc_write
+};
+
+static struct file_operations info_proc_file_ops = {
+ .owner = THIS_MODULE,
+ .open = info_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static struct file_operations nodeinfo_proc_file_ops = {
+ .owner = THIS_MODULE,
+ .open = nodeinfo_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static struct dgrp_proc_entry dgrp_table[] = {
+ {
+ .id = DGRP_CONFIG,
+ .name = "config",
+ .mode = 0644,
+ .proc_file_ops = &config_proc_file_ops,
+ },
+ {
+ .id = DGRP_INFO,
+ .name = "info",
+ .mode = 0644,
+ .proc_file_ops = &info_proc_file_ops,
+ },
+ {
+ .id = DGRP_NODEINFO,
+ .name = "nodeinfo",
+ .mode = 0644,
+ .proc_file_ops = &nodeinfo_proc_file_ops,
+ },
+ {
+ .id = DGRP_NETDIR,
+ .name = "net",
+ .mode = 0500,
+ .child = dgrp_net_table
+ },
+ {
+ .id = DGRP_MONDIR,
+ .name = "mon",
+ .mode = 0500,
+ .child = dgrp_mon_table
+ },
+ {
+ .id = DGRP_PORTSDIR,
+ .name = "ports",
+ .mode = 0500,
+ .child = dgrp_ports_table
+ },
+ {
+ .id = DGRP_DPADIR,
+ .name = "dpa",
+ .mode = 0500,
+ .child = dgrp_dpa_table
+ }
+};
+
+static struct proc_dir_entry *net_entry_pointer;
+static struct proc_dir_entry *mon_entry_pointer;
+static struct proc_dir_entry *dpa_entry_pointer;
+static struct proc_dir_entry *ports_entry_pointer;
+
+static struct dgrp_proc_entry dgrp_net_table[] = {
+ {0}
+};
+
+static struct dgrp_proc_entry dgrp_mon_table[] = {
+ {0}
+};
+
+static struct dgrp_proc_entry dgrp_ports_table[] = {
+ {0}
+};
+
+static struct dgrp_proc_entry dgrp_dpa_table[] = {
+ {0}
+};
+
+void dgrp_unregister_proc(void)
+{
+ unregister_proc_table(dgrp_table, dgrp_proc_dir_entry);
+ net_entry_pointer = NULL;
+ mon_entry_pointer = NULL;
+ dpa_entry_pointer = NULL;
+ ports_entry_pointer = NULL;
+
+ if (dgrp_proc_dir_entry) {
+ remove_proc_entry(dgrp_proc_dir_entry->name,
+ dgrp_proc_dir_entry->parent);
+ dgrp_proc_dir_entry = NULL;
+ }
+
+}
+
+void dgrp_register_proc(void)
+{
+ /*
+ * Register /proc/dgrp
+ */
+ dgrp_proc_dir_entry = proc_create("dgrp", S_IFDIR, NULL,
+ &dgrp_proc_file_ops);
+ register_proc_table(dgrp_table, dgrp_proc_dir_entry);
+}
+
+/*
+ * /proc/sys support
+ */
+static int dgrp_proc_match(int len, const char *name, struct proc_dir_entry *de)
+{
+ if (!de || !de->low_ino)
+ return 0;
+ if (de->namelen != len)
+ return 0;
+ return !memcmp(name, de->name, len);
+}
+
+
+/*
+ * Scan the entries in table and add them all to /proc at the position
+ * referred to by "root"
+ */
+static void register_proc_table(struct dgrp_proc_entry *table,
+ struct proc_dir_entry *root)
+{
+ struct proc_dir_entry *de;
+ int len;
+ mode_t mode;
+
+ for (; table->id; table++) {
+ /* Can't do anything without a proc name. */
+ if (!table->name)
+ continue;
+
+ /* Maybe we can't do anything with it... */
+ if (!table->proc_file_ops &&
+ !table->child) {
+ pr_warn("dgrp: Can't register %s\n",
+ table->name);
+ continue;
+ }
+
+ len = strlen(table->name);
+ mode = table->mode;
+
+ de = NULL;
+ if (!table->child)
+ mode |= S_IFREG;
+ else {
+ mode |= S_IFDIR;
+ for (de = root->subdir; de; de = de->next) {
+ if (dgrp_proc_match(len, table->name, de))
+ break;
+ }
+ /* If the subdir exists already, de is non-NULL */
+ }
+
+ if (!de) {
+ de = create_proc_entry(table->name, mode, root);
+ if (!de)
+ continue;
+ de->data = (void *) table;
+ if (!table->child) {
+ de->proc_iops = &proc_inode_ops;
+ if (table->proc_file_ops)
+ de->proc_fops = table->proc_file_ops;
+ else
+ de->proc_fops = &dgrp_proc_file_ops;
+ }
+ }
+ table->de = de;
+ if (de->mode & S_IFDIR)
+ register_proc_table(table->child, de);
+
+ if (table->id == DGRP_NETDIR)
+ net_entry_pointer = de;
+
+ if (table->id == DGRP_MONDIR)
+ mon_entry_pointer = de;
+
+ if (table->id == DGRP_DPADIR)
+ dpa_entry_pointer = de;
+
+ if (table->id == DGRP_PORTSDIR)
+ ports_entry_pointer = de;
+ }
+}
+
+/*
+ * Unregister a /proc sysctl table and any subdirectories.
+ */
+static void unregister_proc_table(struct dgrp_proc_entry *table,
+ struct proc_dir_entry *root)
+{
+ struct proc_dir_entry *de;
+ struct nd_struct *tmp;
+
+ list_for_each_entry(tmp, &nd_struct_list, list) {
+ if ((table == dgrp_net_table) && (tmp->nd_net_de)) {
+ unregister_dgrp_device(tmp->nd_net_de);
+ dgrp_remove_node_class_sysfs_files(tmp);
+ }
+
+ if ((table == dgrp_mon_table) && (tmp->nd_mon_de))
+ unregister_dgrp_device(tmp->nd_mon_de);
+
+ if ((table == dgrp_dpa_table) && (tmp->nd_dpa_de))
+ unregister_dgrp_device(tmp->nd_dpa_de);
+
+ if ((table == dgrp_ports_table) && (tmp->nd_ports_de))
+ unregister_dgrp_device(tmp->nd_ports_de);
+ }
+
+ for (; table->id; table++) {
+ de = table->de;
+
+ if (!de)
+ continue;
+ if (de->mode & S_IFDIR) {
+ if (!table->child) {
+ pr_alert("dgrp: malformed sysctl tree on free\n");
+ continue;
+ }
+ unregister_proc_table(table->child, de);
+
+ /* Don't unregister directories which still have entries */
+ if (de->subdir)
+ continue;
+ }
+
+ /* Don't unregister proc entries that are still being used.. */
+ if ((atomic_read(&de->count)) != 1) {
+ pr_alert("proc entry %s in use, not removing\n",
+ de->name);
+ continue;
+ }
+
+ remove_proc_entry(de->name, de->parent);
+ table->de = NULL;
+ }
+}
+
+static int dgrp_gen_proc_open(struct inode *inode, struct file *file)
+{
+ struct proc_dir_entry *de;
+ struct dgrp_proc_entry *entry;
+ int ret = 0;
+
+ de = (struct proc_dir_entry *) PDE(file->f_dentry->d_inode);
+ if (!de || !de->data) {
+ ret = -ENXIO;
+ goto done;
+ }
+
+ entry = (struct dgrp_proc_entry *) de->data;
+ if (!entry) {
+ ret = -ENXIO;
+ goto done;
+ }
+
+ down(&entry->excl_sem);
+
+ if (entry->excl_cnt)
+ ret = -EBUSY;
+ else
+ entry->excl_cnt++;
+
+ up(&entry->excl_sem);
+
+done:
+ return ret;
+}
+
+static int dgrp_gen_proc_close(struct inode *inode, struct file *file)
+{
+ struct proc_dir_entry *de;
+ struct dgrp_proc_entry *entry;
+
+ de = (struct proc_dir_entry *) PDE(file->f_dentry->d_inode);
+ if (!de || !de->data)
+ goto done;
+
+ entry = (struct dgrp_proc_entry *) de->data;
+ if (!entry)
+ goto done;
+
+ down(&entry->excl_sem);
+
+ if (entry->excl_cnt)
+ entry->excl_cnt = 0;
+
+ up(&entry->excl_sem);
+
+done:
+ return 0;
+}
+
+static void *config_proc_start(struct seq_file *m, loff_t *pos)
+{
+ return seq_list_start_head(&nd_struct_list, *pos);
+}
+
+static void *config_proc_next(struct seq_file *p, void *v, loff_t *pos)
+{
+ return seq_list_next(v, &nd_struct_list, pos);
+}
+
+static void config_proc_stop(struct seq_file *m, void *v)
+{
+}
+
+static int config_proc_show(struct seq_file *m, void *v)
+{
+ struct nd_struct *nd;
+ char tmp_id[4];
+
+ if (v == &nd_struct_list) {
+ seq_puts(m, "#-----------------------------------------------------------------------------\n");
+ seq_puts(m, "# Avail\n");
+ seq_puts(m, "# ID Major State Ports\n");
+ return 0;
+ }
+
+ nd = list_entry(v, struct nd_struct, list);
+
+ ID_TO_CHAR(nd->nd_ID, tmp_id);
+
+ seq_printf(m, " %-2.2s %-5ld %-10.10s %-5d\n",
+ tmp_id,
+ nd->nd_major,
+ ND_STATE_STR(nd->nd_state),
+ nd->nd_chan_count);
+
+ return 0;
+}
+
+static const struct seq_operations proc_config_ops = {
+ .start = config_proc_start,
+ .next = config_proc_next,
+ .stop = config_proc_stop,
+ .show = config_proc_show
+};
+
+static int config_proc_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &proc_config_ops);
+}
+
+
+/*
+ * When writing configuration information, each "record" (i.e. each
+ * write) is treated as an independent request. See the "parse"
+ * description for more details.
+ */
+static ssize_t config_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *pos)
+{
+ ssize_t retval;
+ char *inbuf, *sp;
+ char *line, *ldelim;
+
+ if (count > 32768)
+ return -EINVAL;
+
+ inbuf = sp = vzalloc(count + 1);
+ if (!inbuf)
+ return -ENOMEM;
+
+ if (copy_from_user(inbuf, buffer, count)) {
+ retval = -EFAULT;
+ goto done;
+ }
+
+ inbuf[count] = 0;
+
+ ldelim = "\n";
+
+ line = strpbrk(sp, ldelim);
+ while (line) {
+ *line = 0;
+ retval = parse_write_config(sp);
+ if (retval)
+ goto done;
+
+ sp = line + 1;
+ line = strpbrk(sp, ldelim);
+ }
+
+ retval = count;
+done:
+ vfree(inbuf);
+ return retval;
+}
+
+/*
+ * ------------------------------------------------------------------------
+ *
+ * The following are the functions to parse input
+ *
+ * ------------------------------------------------------------------------
+ */
+static inline char *skip_past_ws(const char *str)
+{
+ while ((*str) && !isspace(*str))
+ ++str;
+
+ return skip_spaces(str);
+}
+
+static int parse_id(char **c, char *cID)
+{
+ int tmp = **c;
+
+ if (isalnum(tmp) || (tmp == '_'))
+ cID[0] = tmp;
+ else
+ return -EINVAL;
+
+ (*c)++; tmp = **c;
+
+ if (isalnum(tmp) || (tmp == '_')) {
+ cID[1] = tmp;
+ (*c)++;
+ } else
+ cID[1] = 0;
+
+ return 0;
+}
+
+static int parse_add_config(char *buf)
+{
+ char *c = buf;
+ int retval;
+ char cID[2];
+ long ID;
+
+ c = skip_past_ws(c);
+
+ retval = parse_id(&c, cID);
+ if (retval < 0)
+ return retval;
+
+ ID = CHAR_TO_ID(cID);
+
+ c = skip_past_ws(c);
+
+ return dgrp_add_id(ID);
+}
+
+static int parse_del_config(char *buf)
+{
+ char *c = buf;
+ int retval;
+ struct nd_struct *nd;
+ char cID[2];
+ long ID;
+ long major;
+
+ c = skip_past_ws(c);
+
+ retval = parse_id(&c, cID);
+ if (retval < 0)
+ return retval;
+
+ ID = CHAR_TO_ID(cID);
+
+ c = skip_past_ws(c);
+
+ retval = kstrtol(c, 10, &major);
+ if (retval)
+ return retval;
+
+ nd = nd_struct_get(major);
+ if (!nd)
+ return -EINVAL;
+
+ if ((nd->nd_major != major) || (nd->nd_ID != ID))
+ return -EINVAL;
+
+ return dgrp_remove_nd(nd);
+}
+
+static int parse_chg_config(char *buf)
+{
+ return -EINVAL;
+}
+
+/*
+ * The passed character buffer represents a single configuration request.
+ * If the first character is a "+", it is parsed as a request to add a
+ * PortServer
+ * If the first character is a "-", it is parsed as a request to delete a
+ * PortServer
+ * If the first character is a "*", it is parsed as a request to change a
+ * PortServer
+ * Any other character (including whitespace) causes the record to be
+ * ignored.
+ */
+static int parse_write_config(char *buf)
+{
+ int retval;
+
+ switch (buf[0]) {
+ case '+':
+ retval = parse_add_config(buf);
+ break;
+ case '-':
+ retval = parse_del_config(buf);
+ break;
+ case '*':
+ retval = parse_chg_config(buf);
+ break;
+ default:
+ retval = -EINVAL;
+ }
+
+ return retval;
+}
+
+static int info_proc_show(struct seq_file *m, void *v)
+{
+ seq_printf(m, "version: %s\n", DIGI_VERSION);
+ seq_puts(m, "register_with_sysfs: 1\n");
+ seq_printf(m, "rawreadok: 0x%08x\t(%d)\n",
+ dgrp_rawreadok, dgrp_rawreadok);
+ seq_printf(m, "pollrate: 0x%08x\t(%d)\n",
+ dgrp_poll_tick, dgrp_poll_tick);
+
+ return 0;
+}
+
+static int info_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, info_proc_show, NULL);
+}
+
+
+static void *nodeinfo_start(struct seq_file *m, loff_t *pos)
+{
+ return seq_list_start_head(&nd_struct_list, *pos);
+}
+
+static void *nodeinfo_next(struct seq_file *p, void *v, loff_t *pos)
+{
+ return seq_list_next(v, &nd_struct_list, pos);
+}
+
+static void nodeinfo_stop(struct seq_file *m, void *v)
+{
+}
+
+static int nodeinfo_show(struct seq_file *m, void *v)
+{
+ struct nd_struct *nd;
+ char hwver[8];
+ char swver[8];
+ char tmp_id[4];
+
+ if (v == &nd_struct_list) {
+ seq_puts(m, "#-----------------------------------------------------------------------------\n");
+ seq_puts(m, "# HW HW SW\n");
+ seq_puts(m, "# ID State Version ID Version Description\n");
+ return 0;
+ }
+
+ nd = list_entry(v, struct nd_struct, list);
+
+ ID_TO_CHAR(nd->nd_ID, tmp_id);
+
+ if (nd->nd_state == NS_READY) {
+ sprintf(hwver, "%d.%d", (nd->nd_hw_ver >> 8) & 0xff,
+ nd->nd_hw_ver & 0xff);
+ sprintf(swver, "%d.%d", (nd->nd_sw_ver >> 8) & 0xff,
+ nd->nd_sw_ver & 0xff);
+ seq_printf(m, " %-2.2s %-10.10s %-7.7s %-3d %-7.7s %-35.35s\n",
+ tmp_id,
+ ND_STATE_STR(nd->nd_state),
+ hwver,
+ nd->nd_hw_id,
+ swver,
+ nd->nd_ps_desc);
+
+ } else {
+ seq_printf(m, " %-2.2s %-10.10s\n",
+ tmp_id,
+ ND_STATE_STR(nd->nd_state));
+ }
+
+ return 0;
+}
+
+
+static const struct seq_operations nodeinfo_ops = {
+ .start = nodeinfo_start,
+ .next = nodeinfo_next,
+ .stop = nodeinfo_stop,
+ .show = nodeinfo_show
+};
+
+static int nodeinfo_proc_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &nodeinfo_ops);
+}
+
+/**
+ * dgrp_add_id() -- creates new nd struct and adds it to list
+ * @id: id of device to add
+ */
+static int dgrp_add_id(long id)
+{
+ struct nd_struct *nd;
+ int ret;
+ int i;
+
+ nd = kzalloc(sizeof(struct nd_struct), GFP_KERNEL);
+ if (!nd)
+ return -ENOMEM;
+
+ nd->nd_major = 0;
+ nd->nd_ID = id;
+
+ spin_lock_init(&nd->nd_lock);
+
+ init_waitqueue_head(&nd->nd_tx_waitq);
+ init_waitqueue_head(&nd->nd_mon_wqueue);
+ init_waitqueue_head(&nd->nd_dpa_wqueue);
+ for (i = 0; i < SEQ_MAX; i++)
+ init_waitqueue_head(&nd->nd_seq_wque[i]);
+
+ /* setup the structures to get the major number */
+ ret = dgrp_tty_init(nd);
+ if (ret)
+ goto error_out;
+
+ nd->nd_major = nd->nd_serial_ttdriver->major;
+
+ ret = nd_struct_add(nd);
+ if (ret)
+ goto error_out;
+
+ register_dgrp_device(nd, net_entry_pointer, dgrp_register_net_hook);
+ register_dgrp_device(nd, mon_entry_pointer, dgrp_register_mon_hook);
+ register_dgrp_device(nd, dpa_entry_pointer, dgrp_register_dpa_hook);
+ register_dgrp_device(nd, ports_entry_pointer,
+ dgrp_register_ports_hook);
+
+ return 0;
+
+error_out:
+ kfree(nd);
+ return ret;
+
+}
+
+static int dgrp_remove_nd(struct nd_struct *nd)
+{
+ int ret;
+
+ /* Check to see if the selected structure is in use */
+ if (nd->nd_tty_ref_cnt)
+ return -EBUSY;
+
+ if (nd->nd_net_de) {
+ unregister_dgrp_device(nd->nd_net_de);
+ dgrp_remove_node_class_sysfs_files(nd);
+ }
+
+ if (nd->nd_mon_de)
+ unregister_dgrp_device(nd->nd_mon_de);
+
+ if (nd->nd_ports_de)
+ unregister_dgrp_device(nd->nd_ports_de);
+
+ if (nd->nd_dpa_de)
+ unregister_dgrp_device(nd->nd_dpa_de);
+
+ dgrp_tty_uninit(nd);
+
+ ret = nd_struct_del(nd);
+ if (ret)
+ return ret;
+
+ kfree(nd);
+ return 0;
+}
+
+static void register_dgrp_device(struct nd_struct *node,
+ struct proc_dir_entry *root,
+ void (*register_hook)(struct proc_dir_entry *de))
+{
+ char buf[3];
+ struct proc_dir_entry *de;
+
+ ID_TO_CHAR(node->nd_ID, buf);
+
+ de = create_proc_entry(buf, 0600 | S_IFREG, root);
+ if (!de)
+ return;
+
+ de->data = (void *) node;
+
+ if (register_hook)
+ register_hook(de);
+
+}
+
+static void unregister_dgrp_device(struct proc_dir_entry *de)
+{
+ if (!de)
+ return;
+
+ /* Don't unregister proc entries that are still being used.. */
+ if ((atomic_read(&de->count)) != 1) {
+ pr_alert("%s - proc entry %s in use. Not removing.\n",
+ __func__, de->name);
+ return;
+ }
+
+ remove_proc_entry(de->name, de->parent);
+ de = NULL;
+}
diff --git a/drivers/staging/dgrp/dgrp_sysfs.c b/drivers/staging/dgrp/dgrp_sysfs.c
new file mode 100644
index 000000000000..e5a3c88d016e
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_sysfs.c
@@ -0,0 +1,555 @@
+/*
+ * Copyright 2004 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ */
+
+#include "dgrp_common.h"
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/serial_reg.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+
+
+#define PORTSERVER_DIVIDEND 1843200
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
+#define SERIAL_TYPE_XPRINT 3
+
+
+static struct class *dgrp_class;
+static struct device *dgrp_class_nodes_dev;
+static struct device *dgrp_class_global_settings_dev;
+
+
+static ssize_t dgrp_class_version_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", DIGI_VERSION);
+}
+static CLASS_ATTR(driver_version, 0400, dgrp_class_version_show, NULL);
+
+
+static ssize_t dgrp_class_register_with_sysfs_show(struct device *c,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "1\n");
+}
+static DEVICE_ATTR(register_with_sysfs, 0400,
+ dgrp_class_register_with_sysfs_show, NULL);
+
+
+static ssize_t dgrp_class_rawreadok_show(struct device *c,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", dgrp_rawreadok);
+}
+static ssize_t dgrp_class_rawreadok_store(struct device *c,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ sscanf(buf, "0x%x\n", &dgrp_rawreadok);
+ return count;
+}
+static DEVICE_ATTR(rawreadok, 0600, dgrp_class_rawreadok_show,
+ dgrp_class_rawreadok_store);
+
+
+static ssize_t dgrp_class_pollrate_show(struct device *c,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", dgrp_poll_tick);
+}
+
+static ssize_t dgrp_class_pollrate_store(struct device *c,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ sscanf(buf, "0x%x\n", &dgrp_poll_tick);
+ return count;
+}
+static DEVICE_ATTR(pollrate, 0600, dgrp_class_pollrate_show,
+ dgrp_class_pollrate_store);
+
+static struct attribute *dgrp_sysfs_global_settings_entries[] = {
+ &dev_attr_pollrate.attr,
+ &dev_attr_rawreadok.attr,
+ &dev_attr_register_with_sysfs.attr,
+ NULL
+};
+
+
+static struct attribute_group dgrp_global_settings_attribute_group = {
+ .name = NULL,
+ .attrs = dgrp_sysfs_global_settings_entries,
+};
+
+
+
+void dgrp_create_class_sysfs_files(void)
+{
+ int ret = 0;
+ int max_majors = 1U << (32 - MINORBITS);
+
+ dgrp_class = class_create(THIS_MODULE, "digi_realport");
+ ret = class_create_file(dgrp_class, &class_attr_driver_version);
+
+ dgrp_class_global_settings_dev = device_create(dgrp_class, NULL,
+ MKDEV(0, max_majors + 1), NULL, "driver_settings");
+
+ ret = sysfs_create_group(&dgrp_class_global_settings_dev->kobj,
+ &dgrp_global_settings_attribute_group);
+ if (ret) {
+ pr_alert("%s: failed to create sysfs global settings device attributes.\n",
+ __func__);
+ sysfs_remove_group(&dgrp_class_global_settings_dev->kobj,
+ &dgrp_global_settings_attribute_group);
+ return;
+ }
+
+ dgrp_class_nodes_dev = device_create(dgrp_class, NULL,
+ MKDEV(0, max_majors + 2), NULL, "nodes");
+
+}
+
+
+void dgrp_remove_class_sysfs_files(void)
+{
+ struct nd_struct *nd;
+ int max_majors = 1U << (32 - MINORBITS);
+
+ list_for_each_entry(nd, &nd_struct_list, list)
+ dgrp_remove_node_class_sysfs_files(nd);
+
+ sysfs_remove_group(&dgrp_class_global_settings_dev->kobj,
+ &dgrp_global_settings_attribute_group);
+
+ class_remove_file(dgrp_class, &class_attr_driver_version);
+
+ device_destroy(dgrp_class, MKDEV(0, max_majors + 1));
+ device_destroy(dgrp_class, MKDEV(0, max_majors + 2));
+ class_destroy(dgrp_class);
+}
+
+static ssize_t dgrp_node_state_show(struct device *c,
+ struct device_attribute *attr, char *buf)
+{
+ struct nd_struct *nd;
+
+ if (!c)
+ return 0;
+ nd = (struct nd_struct *) dev_get_drvdata(c);
+ if (!nd)
+ return 0;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", ND_STATE_STR(nd->nd_state));
+}
+
+static DEVICE_ATTR(state, 0600, dgrp_node_state_show, NULL);
+
+static ssize_t dgrp_node_description_show(struct device *c,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct nd_struct *nd;
+
+ if (!c)
+ return 0;
+ nd = (struct nd_struct *) dev_get_drvdata(c);
+ if (!nd)
+ return 0;
+
+ if (nd->nd_state == NS_READY && nd->nd_ps_desc)
+ return snprintf(buf, PAGE_SIZE, "%s\n", nd->nd_ps_desc);
+ return 0;
+}
+static DEVICE_ATTR(description_info, 0600, dgrp_node_description_show, NULL);
+
+static ssize_t dgrp_node_hw_version_show(struct device *c,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct nd_struct *nd;
+
+ if (!c)
+ return 0;
+ nd = (struct nd_struct *) dev_get_drvdata(c);
+ if (!nd)
+ return 0;
+
+ if (nd->nd_state == NS_READY)
+ return snprintf(buf, PAGE_SIZE, "%d.%d\n",
+ (nd->nd_hw_ver >> 8) & 0xff,
+ nd->nd_hw_ver & 0xff);
+
+ return 0;
+}
+static DEVICE_ATTR(hw_version_info, 0600, dgrp_node_hw_version_show, NULL);
+
+static ssize_t dgrp_node_hw_id_show(struct device *c,
+ struct device_attribute *attr, char *buf)
+{
+ struct nd_struct *nd;
+
+ if (!c)
+ return 0;
+ nd = (struct nd_struct *) dev_get_drvdata(c);
+ if (!nd)
+ return 0;
+
+
+ if (nd->nd_state == NS_READY)
+ return snprintf(buf, PAGE_SIZE, "%d\n", nd->nd_hw_id);
+ return 0;
+}
+static DEVICE_ATTR(hw_id_info, 0600, dgrp_node_hw_id_show, NULL);
+
+static ssize_t dgrp_node_sw_version_show(struct device *c,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct nd_struct *nd;
+
+ if (!c)
+ return 0;
+
+ nd = (struct nd_struct *) dev_get_drvdata(c);
+ if (!nd)
+ return 0;
+
+ if (nd->nd_state == NS_READY)
+ return snprintf(buf, PAGE_SIZE, "%d.%d\n",
+ (nd->nd_sw_ver >> 8) & 0xff,
+ nd->nd_sw_ver & 0xff);
+
+ return 0;
+}
+static DEVICE_ATTR(sw_version_info, 0600, dgrp_node_sw_version_show, NULL);
+
+
+static struct attribute *dgrp_sysfs_node_entries[] = {
+ &dev_attr_state.attr,
+ &dev_attr_description_info.attr,
+ &dev_attr_hw_version_info.attr,
+ &dev_attr_hw_id_info.attr,
+ &dev_attr_sw_version_info.attr,
+ NULL
+};
+
+
+static struct attribute_group dgrp_node_attribute_group = {
+ .name = NULL,
+ .attrs = dgrp_sysfs_node_entries,
+};
+
+
+void dgrp_create_node_class_sysfs_files(struct nd_struct *nd)
+{
+ int ret;
+ char name[10];
+
+ if (nd->nd_ID)
+ ID_TO_CHAR(nd->nd_ID, name);
+ else
+ sprintf(name, "node%ld", nd->nd_major);
+
+ nd->nd_class_dev = device_create(dgrp_class, dgrp_class_nodes_dev,
+ MKDEV(0, nd->nd_major), NULL, name);
+
+ ret = sysfs_create_group(&nd->nd_class_dev->kobj,
+ &dgrp_node_attribute_group);
+
+ if (ret) {
+ pr_alert("%s: failed to create sysfs node device attributes.\n",
+ __func__);
+ sysfs_remove_group(&nd->nd_class_dev->kobj,
+ &dgrp_node_attribute_group);
+ return;
+ }
+
+ dev_set_drvdata(nd->nd_class_dev, nd);
+
+}
+
+
+void dgrp_remove_node_class_sysfs_files(struct nd_struct *nd)
+{
+ if (nd->nd_class_dev) {
+ sysfs_remove_group(&nd->nd_class_dev->kobj,
+ &dgrp_node_attribute_group);
+
+ device_destroy(dgrp_class, MKDEV(0, nd->nd_major));
+ nd->nd_class_dev = NULL;
+ }
+}
+
+
+
+static ssize_t dgrp_tty_state_show(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct un_struct *un;
+
+ if (!d)
+ return 0;
+ un = (struct un_struct *) dev_get_drvdata(d);
+ if (!un)
+ return 0;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ un->un_open_count ? "Open" : "Closed");
+}
+static DEVICE_ATTR(state_info, 0600, dgrp_tty_state_show, NULL);
+
+static ssize_t dgrp_tty_baud_show(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct ch_struct *ch;
+ struct un_struct *un;
+
+ if (!d)
+ return 0;
+ un = (struct un_struct *) dev_get_drvdata(d);
+ if (!un)
+ return 0;
+ ch = un->un_ch;
+ if (!ch)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ un->un_open_count ? (PORTSERVER_DIVIDEND / ch->ch_s_brate) : 0);
+}
+static DEVICE_ATTR(baud_info, 0400, dgrp_tty_baud_show, NULL);
+
+
+static ssize_t dgrp_tty_msignals_show(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct ch_struct *ch;
+ struct un_struct *un;
+
+ if (!d)
+ return 0;
+ un = (struct un_struct *) dev_get_drvdata(d);
+ if (!un)
+ return 0;
+ ch = un->un_ch;
+ if (!ch)
+ return 0;
+
+ if (ch->ch_open_count) {
+ return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n",
+ (ch->ch_s_mlast & DM_RTS) ? "RTS" : "",
+ (ch->ch_s_mlast & DM_CTS) ? "CTS" : "",
+ (ch->ch_s_mlast & DM_DTR) ? "DTR" : "",
+ (ch->ch_s_mlast & DM_DSR) ? "DSR" : "",
+ (ch->ch_s_mlast & DM_CD) ? "DCD" : "",
+ (ch->ch_s_mlast & DM_RI) ? "RI" : "");
+ }
+ return 0;
+}
+static DEVICE_ATTR(msignals_info, 0400, dgrp_tty_msignals_show, NULL);
+
+
+static ssize_t dgrp_tty_iflag_show(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct ch_struct *ch;
+ struct un_struct *un;
+
+ if (!d)
+ return 0;
+ un = (struct un_struct *) dev_get_drvdata(d);
+ if (!un)
+ return 0;
+ ch = un->un_ch;
+ if (!ch)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_s_iflag);
+}
+static DEVICE_ATTR(iflag_info, 0600, dgrp_tty_iflag_show, NULL);
+
+
+static ssize_t dgrp_tty_cflag_show(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct ch_struct *ch;
+ struct un_struct *un;
+
+ if (!d)
+ return 0;
+ un = (struct un_struct *) dev_get_drvdata(d);
+ if (!un)
+ return 0;
+ ch = un->un_ch;
+ if (!ch)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_s_cflag);
+}
+static DEVICE_ATTR(cflag_info, 0600, dgrp_tty_cflag_show, NULL);
+
+
+static ssize_t dgrp_tty_oflag_show(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct ch_struct *ch;
+ struct un_struct *un;
+
+ if (!d)
+ return 0;
+ un = (struct un_struct *) dev_get_drvdata(d);
+ if (!un)
+ return 0;
+ ch = un->un_ch;
+ if (!ch)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_s_oflag);
+}
+static DEVICE_ATTR(oflag_info, 0600, dgrp_tty_oflag_show, NULL);
+
+
+static ssize_t dgrp_tty_digi_flag_show(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct ch_struct *ch;
+ struct un_struct *un;
+
+ if (!d)
+ return 0;
+ un = (struct un_struct *) dev_get_drvdata(d);
+ if (!un)
+ return 0;
+ ch = un->un_ch;
+ if (!ch)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags);
+}
+static DEVICE_ATTR(digi_flag_info, 0600, dgrp_tty_digi_flag_show, NULL);
+
+
+static ssize_t dgrp_tty_rxcount_show(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct ch_struct *ch;
+ struct un_struct *un;
+
+ if (!d)
+ return 0;
+ un = (struct un_struct *) dev_get_drvdata(d);
+ if (!un)
+ return 0;
+ ch = un->un_ch;
+ if (!ch)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_rxcount);
+}
+static DEVICE_ATTR(rxcount_info, 0600, dgrp_tty_rxcount_show, NULL);
+
+
+static ssize_t dgrp_tty_txcount_show(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct ch_struct *ch;
+ struct un_struct *un;
+
+ if (!d)
+ return 0;
+ un = (struct un_struct *) dev_get_drvdata(d);
+ if (!un)
+ return 0;
+ ch = un->un_ch;
+ if (!ch)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_txcount);
+}
+static DEVICE_ATTR(txcount_info, 0600, dgrp_tty_txcount_show, NULL);
+
+
+static ssize_t dgrp_tty_name_show(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct nd_struct *nd;
+ struct ch_struct *ch;
+ struct un_struct *un;
+ char name[10];
+
+ if (!d)
+ return 0;
+ un = (struct un_struct *) dev_get_drvdata(d);
+ if (!un)
+ return 0;
+ ch = un->un_ch;
+ if (!ch)
+ return 0;
+ nd = ch->ch_nd;
+ if (!nd)
+ return 0;
+
+ ID_TO_CHAR(nd->nd_ID, name);
+
+ return snprintf(buf, PAGE_SIZE, "%s%s%02d\n",
+ un->un_type == SERIAL_TYPE_XPRINT ? "pr" : "tty",
+ name, ch->ch_portnum);
+}
+static DEVICE_ATTR(custom_name, 0600, dgrp_tty_name_show, NULL);
+
+
+static struct attribute *dgrp_sysfs_tty_entries[] = {
+ &dev_attr_state_info.attr,
+ &dev_attr_baud_info.attr,
+ &dev_attr_msignals_info.attr,
+ &dev_attr_iflag_info.attr,
+ &dev_attr_cflag_info.attr,
+ &dev_attr_oflag_info.attr,
+ &dev_attr_digi_flag_info.attr,
+ &dev_attr_rxcount_info.attr,
+ &dev_attr_txcount_info.attr,
+ &dev_attr_custom_name.attr,
+ NULL
+};
+
+
+static struct attribute_group dgrp_tty_attribute_group = {
+ .name = NULL,
+ .attrs = dgrp_sysfs_tty_entries,
+};
+
+
+void dgrp_create_tty_sysfs(struct un_struct *un, struct device *c)
+{
+ int ret;
+
+ ret = sysfs_create_group(&c->kobj, &dgrp_tty_attribute_group);
+ if (ret) {
+ pr_alert("%s: failed to create sysfs tty device attributes.\n",
+ __func__);
+ sysfs_remove_group(&c->kobj, &dgrp_tty_attribute_group);
+ return;
+ }
+
+ dev_set_drvdata(c, un);
+
+}
+
+
+void dgrp_remove_tty_sysfs(struct device *c)
+{
+ sysfs_remove_group(&c->kobj, &dgrp_tty_attribute_group);
+}
diff --git a/drivers/staging/dgrp/dgrp_tty.c b/drivers/staging/dgrp/dgrp_tty.c
new file mode 100644
index 000000000000..7d7de873870c
--- /dev/null
+++ b/drivers/staging/dgrp/dgrp_tty.c
@@ -0,0 +1,3331 @@
+/*
+ *
+ * Copyright 1999 Digi International (www.digi.com)
+ * Gene Olson <Gene_Olson at digi dot com>
+ * James Puzzo <jamesp at digi dot com>
+ * Jeff Randall
+ * Scott Kilau <scottk at digi dot com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ */
+
+/*
+ *
+ * Filename:
+ *
+ * dgrp_tty.c
+ *
+ * Description:
+ *
+ * This file implements the tty driver functionality for the
+ * RealPort driver software.
+ *
+ * Author:
+ *
+ * James A. Puzzo
+ * Ann-Marie Westgate
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/sched.h>
+
+#include "dgrp_common.h"
+
+#ifndef _POSIX_VDISABLE
+#define _POSIX_VDISABLE ('\0')
+#endif
+
+/*
+ * forward declarations
+ */
+
+static void drp_param(struct ch_struct *);
+static void dgrp_tty_close(struct tty_struct *, struct file *);
+
+/* ioctl helper functions */
+static int set_modem_info(struct ch_struct *, unsigned int, unsigned int *);
+static int get_modem_info(struct ch_struct *, unsigned int *);
+static void dgrp_set_custom_speed(struct ch_struct *, int);
+static int dgrp_tty_digigetedelay(struct tty_struct *, int *);
+static int dgrp_tty_digisetedelay(struct tty_struct *, int *);
+static int dgrp_send_break(struct ch_struct *, int);
+
+static ushort tty_to_ch_flags(struct tty_struct *, char);
+static tcflag_t ch_to_tty_flags(unsigned short, char);
+
+static void dgrp_tty_input_start(struct tty_struct *);
+static void dgrp_tty_input_stop(struct tty_struct *);
+
+static void drp_wmove(struct ch_struct *, int, void*, int);
+
+static int dgrp_tty_open(struct tty_struct *, struct file *);
+static void dgrp_tty_close(struct tty_struct *, struct file *);
+static int dgrp_tty_write(struct tty_struct *, const unsigned char *, int);
+static int dgrp_tty_write_room(struct tty_struct *);
+static void dgrp_tty_flush_buffer(struct tty_struct *);
+static int dgrp_tty_chars_in_buffer(struct tty_struct *);
+static int dgrp_tty_ioctl(struct tty_struct *, unsigned int, unsigned long);
+static void dgrp_tty_set_termios(struct tty_struct *, struct ktermios *);
+static void dgrp_tty_stop(struct tty_struct *);
+static void dgrp_tty_start(struct tty_struct *);
+static void dgrp_tty_throttle(struct tty_struct *);
+static void dgrp_tty_unthrottle(struct tty_struct *);
+static void dgrp_tty_hangup(struct tty_struct *);
+static int dgrp_tty_put_char(struct tty_struct *, unsigned char);
+static int dgrp_tty_tiocmget(struct tty_struct *);
+static int dgrp_tty_tiocmset(struct tty_struct *, unsigned int, unsigned int);
+static int dgrp_tty_send_break(struct tty_struct *, int);
+static void dgrp_tty_send_xchar(struct tty_struct *, char);
+
+/*
+ * tty defines
+ */
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
+#define SERIAL_TYPE_XPRINT 3
+
+
+/*
+ * tty globals/statics
+ */
+
+
+#define PORTSERVER_DIVIDEND 1843200
+
+/*
+ * Default transparent print information.
+ */
+static struct digi_struct digi_init = {
+ .digi_flags = DIGI_COOK, /* Flags */
+ .digi_maxcps = 100, /* Max CPS */
+ .digi_maxchar = 50, /* Max chars in print queue */
+ .digi_bufsize = 100, /* Printer buffer size */
+ .digi_onlen = 4, /* size of printer on string */
+ .digi_offlen = 4, /* size of printer off string */
+ .digi_onstr = "\033[5i", /* ANSI printer on string */
+ .digi_offstr = "\033[4i", /* ANSI printer off string */
+ .digi_term = "ansi" /* default terminal type */
+};
+
+/*
+ * Define a local default termios struct. All ports will be created
+ * with this termios initially.
+ *
+ * This defines a raw port at 9600 baud, 8 data bits, no parity,
+ * 1 stop bit.
+ */
+static struct ktermios DefaultTermios = {
+ .c_iflag = (ICRNL | IXON),
+ .c_oflag = (OPOST | ONLCR),
+ .c_cflag = (B9600 | CS8 | CREAD | HUPCL | CLOCAL),
+ .c_lflag = (ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL
+ | ECHOKE | IEXTEN),
+ .c_cc = INIT_C_CC,
+ .c_line = 0,
+};
+
+/* Define our tty operations struct */
+static const struct tty_operations dgrp_tty_ops = {
+ .open = dgrp_tty_open,
+ .close = dgrp_tty_close,
+ .write = dgrp_tty_write,
+ .write_room = dgrp_tty_write_room,
+ .flush_buffer = dgrp_tty_flush_buffer,
+ .chars_in_buffer = dgrp_tty_chars_in_buffer,
+ .flush_chars = NULL,
+ .ioctl = dgrp_tty_ioctl,
+ .set_termios = dgrp_tty_set_termios,
+ .stop = dgrp_tty_stop,
+ .start = dgrp_tty_start,
+ .throttle = dgrp_tty_throttle,
+ .unthrottle = dgrp_tty_unthrottle,
+ .hangup = dgrp_tty_hangup,
+ .put_char = dgrp_tty_put_char,
+ .tiocmget = dgrp_tty_tiocmget,
+ .tiocmset = dgrp_tty_tiocmset,
+ .break_ctl = dgrp_tty_send_break,
+ .send_xchar = dgrp_tty_send_xchar
+};
+
+
+static int calc_baud_rate(struct un_struct *un)
+{
+ int i;
+ int brate;
+
+ struct baud_rates {
+ unsigned int rate;
+ unsigned int cflag;
+ };
+
+ static struct baud_rates baud_rates[] = {
+ { 921600, B921600 },
+ { 460800, B460800 },
+ { 230400, B230400 },
+ { 115200, B115200 },
+ { 57600, B57600 },
+ { 38400, B38400 },
+ { 19200, B19200 },
+ { 9600, B9600 },
+ { 4800, B4800 },
+ { 2400, B2400 },
+ { 1200, B1200 },
+ { 600, B600 },
+ { 300, B300 },
+ { 200, B200 },
+ { 150, B150 },
+ { 134, B134 },
+ { 110, B110 },
+ { 75, B75 },
+ { 50, B50 },
+ { 0, B9600 }
+ };
+
+ brate = C_BAUD(un->un_tty);
+
+ for (i = 0; baud_rates[i].rate; i++) {
+ if (baud_rates[i].cflag == brate)
+ break;
+ }
+
+ return baud_rates[i].rate;
+}
+
+static int calc_fastbaud_rate(struct un_struct *un, struct ktermios *uts)
+{
+ int i;
+ int brate;
+
+ ulong bauds[2][16] = {
+ { /* fastbaud*/
+ 0, 57600, 76800, 115200,
+ 131657, 153600, 230400, 460800,
+ 921600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 },
+ { /* fastbaud & CBAUDEX */
+ 0, 57600, 115200, 230400,
+ 460800, 150, 200, 921600,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 }
+ };
+
+ brate = C_BAUD(un->un_tty) & 0xff;
+
+ i = (uts->c_cflag & CBAUDEX) ? 1 : 0;
+
+
+ if ((i >= 0) && (i < 2) && (brate >= 0) && (brate < 16))
+ brate = bauds[i][brate];
+ else
+ brate = 0;
+
+ return brate;
+}
+
+/**
+ * drp_param() -- send parameter values to be sent to the node
+ * @ch: channel structure of port to modify
+ *
+ * Interprets the tty and modem changes made by an application
+ * program (by examining the termios structures) and sets up
+ * parameter values to be sent to the node.
+ */
+static void drp_param(struct ch_struct *ch)
+{
+ struct nd_struct *nd;
+ struct un_struct *un;
+ int brate;
+ int mflow;
+ int xflag;
+ int iflag;
+ struct ktermios *tts, *pts, *uts;
+
+ nd = ch->ch_nd;
+
+ /*
+ * If the terminal device is open, use it to set up all tty
+ * modes and functions. Otherwise use the printer device.
+ */
+
+ if (ch->ch_tun.un_open_count) {
+
+ un = &ch->ch_tun;
+ tts = &ch->ch_tun.un_tty->termios;
+
+ /*
+ * If both devices are open, copy critical line
+ * parameters from the tty device to the printer,
+ * so that if the tty is closed, the printer will
+ * continue without disruption.
+ */
+
+ if (ch->ch_pun.un_open_count) {
+
+ pts = &ch->ch_pun.un_tty->termios;
+
+ pts->c_cflag ^=
+ (pts->c_cflag ^ tts->c_cflag) &
+ (CBAUD | CSIZE | CSTOPB | CREAD | PARENB |
+ PARODD | HUPCL | CLOCAL);
+
+ pts->c_iflag ^=
+ (pts->c_iflag ^ tts->c_iflag) &
+ (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK |
+ ISTRIP | IXON | IXANY | IXOFF);
+
+ pts->c_cc[VSTART] = tts->c_cc[VSTART];
+ pts->c_cc[VSTOP] = tts->c_cc[VSTOP];
+ }
+ } else if (ch->ch_pun.un_open_count == 0) {
+ pr_warn("%s - ch_pun.un_open_count shouldn't be 0\n",
+ __func__);
+ return;
+ } else {
+ un = &ch->ch_pun;
+ }
+
+ uts = &un->un_tty->termios;
+
+ /*
+ * Determine if FAST writes can be performed.
+ */
+
+ if ((ch->ch_digi.digi_flags & DIGI_COOK) != 0 &&
+ (ch->ch_tun.un_open_count != 0) &&
+ !((un->un_tty)->ldisc->ops->flags & LDISC_FLAG_DEFINED) &&
+ !(L_XCASE(un->un_tty))) {
+ ch->ch_flag |= CH_FAST_WRITE;
+ } else {
+ ch->ch_flag &= ~CH_FAST_WRITE;
+ }
+
+ /*
+ * If FAST writes can be performed, and OPOST is on in the
+ * terminal device, do OPOST handling in the server.
+ */
+
+ if ((ch->ch_flag & CH_FAST_WRITE) &&
+ O_OPOST(un->un_tty) != 0) {
+ int oflag = tty_to_ch_flags(un->un_tty, 'o');
+
+ /* add to ch_ocook any processing flags set in the termio */
+ ch->ch_ocook |= oflag & (OF_OLCUC |
+ OF_ONLCR |
+ OF_OCRNL |
+ OF_ONLRET |
+ OF_TABDLY);
+
+ /*
+ * the hpux driver clears any flags set in ch_ocook
+ * from the termios oflag. It is STILL reported though
+ * by a TCGETA
+ */
+
+ oflag = ch_to_tty_flags(ch->ch_ocook, 'o');
+ uts->c_oflag &= ~oflag;
+
+ } else {
+ /* clear the ch->ch_ocook flag */
+ int oflag = ch_to_tty_flags(ch->ch_ocook, 'o');
+ uts->c_oflag |= oflag;
+ ch->ch_ocook = 0;
+ }
+
+ ch->ch_oflag = ch->ch_ocook;
+
+
+ ch->ch_flag &= ~CH_FAST_READ;
+
+ /*
+ * Generate channel flags
+ */
+
+ if (C_BAUD(un->un_tty) == B0) {
+ if (!(ch->ch_flag & CH_BAUD0)) {
+ /* TODO : the HPUX driver flushes line */
+ /* TODO : discipline, I assume I don't have to */
+
+ ch->ch_tout = ch->ch_tin;
+ ch->ch_rout = ch->ch_rin;
+
+ ch->ch_break_time = 0;
+
+ ch->ch_send |= RR_TX_FLUSH | RR_RX_FLUSH;
+
+ ch->ch_mout &= ~(DM_DTR | DM_RTS);
+
+ ch->ch_flag |= CH_BAUD0;
+ }
+ } else if (ch->ch_custom_speed) {
+ ch->ch_brate = PORTSERVER_DIVIDEND / ch->ch_custom_speed ;
+
+ if (ch->ch_flag & CH_BAUD0) {
+ ch->ch_mout |= DM_DTR | DM_RTS;
+
+ ch->ch_flag &= ~CH_BAUD0;
+ }
+ } else {
+ /*
+ * Baud rate mapping.
+ *
+ * If FASTBAUD isn't on, we can scan the new baud rate list
+ * as required.
+ *
+ * However, if FASTBAUD is on, we must go to the old
+ * baud rate mapping that existed many many moons ago,
+ * for compatibility reasons.
+ */
+
+ if (!(ch->ch_digi.digi_flags & DIGI_FAST))
+ brate = calc_baud_rate(un);
+ else
+ brate = calc_fastbaud_rate(un, uts);
+
+ if (brate == 0)
+ brate = 9600;
+
+ ch->ch_brate = PORTSERVER_DIVIDEND / brate;
+
+ if (ch->ch_flag & CH_BAUD0) {
+ ch->ch_mout |= DM_DTR | DM_RTS;
+
+ ch->ch_flag &= ~CH_BAUD0;
+ }
+ }
+
+ /*
+ * Generate channel cflags from the termio.
+ */
+
+ ch->ch_cflag = tty_to_ch_flags(un->un_tty, 'c');
+
+ /*
+ * Generate channel iflags from the termio.
+ */
+
+ iflag = (int) tty_to_ch_flags(un->un_tty, 'i');
+
+ if (START_CHAR(un->un_tty) == _POSIX_VDISABLE ||
+ STOP_CHAR(un->un_tty) == _POSIX_VDISABLE) {
+ iflag &= ~(IF_IXON | IF_IXANY | IF_IXOFF);
+ }
+
+ ch->ch_iflag = iflag;
+
+ /*
+ * Generate flow control characters
+ */
+
+ /*
+ * From the POSIX.1 spec (7.1.2.6): "If {_POSIX_VDISABLE}
+ * is defined for the terminal device file, and the value
+ * of one of the changable special control characters (see
+ * 7.1.1.9) is {_POSIX_VDISABLE}, that function shall be
+ * disabled, that is, no input data shall be recognized as
+ * the disabled special character."
+ *
+ * OK, so we don't ever assign S/DXB XON or XOFF to _POSIX_VDISABLE.
+ */
+
+ if (uts->c_cc[VSTART] != _POSIX_VDISABLE)
+ ch->ch_xon = uts->c_cc[VSTART];
+ if (uts->c_cc[VSTOP] != _POSIX_VDISABLE)
+ ch->ch_xoff = uts->c_cc[VSTOP];
+
+ ch->ch_lnext = (uts->c_cc[VLNEXT] == _POSIX_VDISABLE ? 0 :
+ uts->c_cc[VLNEXT]);
+
+ /*
+ * Also, if either c_cc[START] or c_cc[STOP] is set to
+ * _POSIX_VDISABLE, we can't really do software flow
+ * control--in either direction--so we turn it off as
+ * far as S/DXB is concerned. In essence, if you disable
+ * one, you disable the other too.
+ */
+ if ((uts->c_cc[VSTART] == _POSIX_VDISABLE) ||
+ (uts->c_cc[VSTOP] == _POSIX_VDISABLE))
+ ch->ch_iflag &= ~(IF_IXOFF | IF_IXON);
+
+ /*
+ * Update xflags.
+ */
+
+ xflag = 0;
+
+ if (ch->ch_digi.digi_flags & DIGI_AIXON)
+ xflag = XF_XIXON;
+
+ if ((ch->ch_xxon == _POSIX_VDISABLE) ||
+ (ch->ch_xxoff == _POSIX_VDISABLE))
+ xflag &= ~XF_XIXON;
+
+ ch->ch_xflag = xflag;
+
+
+ /*
+ * Figure effective DCD value.
+ */
+
+ if (C_CLOCAL(un->un_tty))
+ ch->ch_flag |= CH_CLOCAL;
+ else
+ ch->ch_flag &= ~CH_CLOCAL;
+
+ /*
+ * Check modem signals
+ */
+
+ dgrp_carrier(ch);
+
+ /*
+ * Get hardware handshake value.
+ */
+
+ mflow = 0;
+
+ if (C_CRTSCTS(un->un_tty))
+ mflow |= (DM_RTS | DM_CTS);
+
+ if (ch->ch_digi.digi_flags & RTSPACE)
+ mflow |= DM_RTS;
+
+ if (ch->ch_digi.digi_flags & DTRPACE)
+ mflow |= DM_DTR;
+
+ if (ch->ch_digi.digi_flags & CTSPACE)
+ mflow |= DM_CTS;
+
+ if (ch->ch_digi.digi_flags & DSRPACE)
+ mflow |= DM_DSR;
+
+ if (ch->ch_digi.digi_flags & DCDPACE)
+ mflow |= DM_CD;
+
+ if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE)
+ mflow |= DM_RTS_TOGGLE;
+
+ ch->ch_mflow = mflow;
+
+ /*
+ * Send the changes to the server.
+ */
+
+ ch->ch_flag |= CH_PARAM;
+ (ch->ch_nd)->nd_tx_work = 1;
+
+ if (waitqueue_active(&ch->ch_flag_wait))
+ wake_up_interruptible(&ch->ch_flag_wait);
+}
+
+/*
+ * This function is just used as a callback for timeouts
+ * waiting on the ch_sleep flag.
+ */
+static void wake_up_drp_sleep_timer(unsigned long ptr)
+{
+ struct ch_struct *ch = (struct ch_struct *) ptr;
+ if (ch)
+ wake_up(&ch->ch_sleep);
+}
+
+
+/*
+ * Set up our own sleep that can't be cancelled
+ * until our timeout occurs.
+ */
+static void drp_my_sleep(struct ch_struct *ch)
+{
+ struct timer_list drp_wakeup_timer;
+ DECLARE_WAITQUEUE(wait, current);
+
+ /*
+ * First make sure we're ready to receive the wakeup.
+ */
+
+ add_wait_queue(&ch->ch_sleep, &wait);
+ current->state = TASK_UNINTERRUPTIBLE;
+
+ /*
+ * Since we are uninterruptible, set a timer to
+ * unset the uninterruptable state in 1 second.
+ */
+
+ init_timer(&drp_wakeup_timer);
+ drp_wakeup_timer.function = wake_up_drp_sleep_timer;
+ drp_wakeup_timer.data = (unsigned long) ch;
+ drp_wakeup_timer.expires = jiffies + (1 * HZ);
+ add_timer(&drp_wakeup_timer);
+
+ schedule();
+
+ del_timer(&drp_wakeup_timer);
+
+ remove_wait_queue(&ch->ch_sleep, &wait);
+}
+
+/*
+ * dgrp_tty_open()
+ *
+ * returns:
+ * -EBUSY - this is a callout device and the normal device is active
+ * - there is an error in opening the tty
+ * -ENODEV - the channel does not exist
+ * -EAGAIN - we are in the middle of hanging up or closing
+ * - IMMEDIATE_OPEN fails
+ * -ENXIO or -EAGAIN
+ * - if the port is outside physical range
+ * -EINTR - the open is interrupted
+ *
+ */
+static int dgrp_tty_open(struct tty_struct *tty, struct file *file)
+{
+ int retval = 0;
+ struct nd_struct *nd;
+ struct ch_struct *ch;
+ struct un_struct *un;
+ int port;
+ int delay_error;
+ int otype;
+ int unf;
+ int wait_carrier;
+ int category;
+ int counts_were_incremented = 0;
+ ulong lock_flags;
+ DECLARE_WAITQUEUE(wait, current);
+
+ /*
+ * Do some initial checks to see if the node and port exist
+ */
+
+ nd = nd_struct_get(MAJOR(tty_devnum(tty)));
+ port = PORT_NUM(MINOR(tty_devnum(tty)));
+ category = OPEN_CATEGORY(MINOR(tty_devnum(tty)));
+
+ if (!nd)
+ return -ENODEV;
+
+ if (port >= CHAN_MAX)
+ return -ENODEV;
+
+ /*
+ * The channel exists.
+ */
+
+ ch = nd->nd_chan + port;
+
+ un = IS_PRINT(MINOR(tty_devnum(tty))) ? &ch->ch_pun : &ch->ch_tun;
+ un->un_tty = tty;
+ tty->driver_data = un;
+
+ /*
+ * If we are in the middle of hanging up,
+ * then return an error
+ */
+ if (tty_hung_up_p(file)) {
+ retval = ((un->un_flag & UN_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+ goto done;
+ }
+
+ /*
+ * If the port is in the middle of closing, then block
+ * until it is done, then try again.
+ */
+ retval = wait_event_interruptible(un->un_close_wait,
+ ((un->un_flag & UN_CLOSING) == 0));
+
+ if (retval)
+ goto done;
+
+ /*
+ * If the port is in the middle of a reopen after a network disconnect,
+ * wait until it is done, then try again.
+ */
+ retval = wait_event_interruptible(ch->ch_flag_wait,
+ ((ch->ch_flag & CH_PORT_GONE) == 0));
+
+ if (retval)
+ goto done;
+
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+
+ if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
+ if (un->un_flag & UN_NORMAL_ACTIVE) {
+ retval = -EBUSY;
+ goto done;
+ } else {
+ un->un_flag |= UN_CALLOUT_ACTIVE;
+ }
+ }
+
+ /*
+ * Loop waiting until the open can be successfully completed.
+ */
+
+ spin_lock_irqsave(&nd->nd_lock, lock_flags);
+
+ nd->nd_tx_work = 1;
+
+ for (;;) {
+ wait_carrier = 0;
+
+ /*
+ * Determine the open type from the flags provided.
+ */
+
+ /*
+ * If the port is not enabled, then exit
+ */
+ if (test_bit(TTY_IO_ERROR, &tty->flags)) {
+ /* there was an error in opening the tty */
+ if (un->un_flag & UN_CALLOUT_ACTIVE)
+ retval = -EBUSY;
+ else
+ un->un_flag |= UN_NORMAL_ACTIVE;
+ goto unlock;
+ }
+
+ if (file->f_flags & O_NONBLOCK) {
+
+ /*
+ * if the O_NONBLOCK is set, errors on read and write
+ * must return -EAGAIN immediately and NOT sleep
+ * on the waitqs.
+ */
+ otype = OTYPE_IMMEDIATE;
+ delay_error = -EAGAIN;
+
+ } else if (!OPEN_WAIT_AVAIL(category) ||
+ (file->f_flags & O_NDELAY) != 0) {
+ otype = OTYPE_IMMEDIATE;
+ delay_error = -EBUSY;
+
+ } else if (!OPEN_WAIT_CARRIER(category) ||
+ ((ch->ch_digi.digi_flags & DIGI_FORCEDCD) != 0) ||
+ C_CLOCAL(tty)) {
+ otype = OTYPE_PERSISTENT;
+ delay_error = 0;
+
+ } else {
+ otype = OTYPE_INCOMING;
+ delay_error = 0;
+ }
+
+ /*
+ * Handle port currently outside physical port range.
+ */
+
+ if (port >= nd->nd_chan_count) {
+ if (otype == OTYPE_IMMEDIATE) {
+ retval = (nd->nd_state == NS_READY) ?
+ -ENXIO : -EAGAIN;
+ goto unlock;
+ }
+ }
+
+ /*
+ * Handle port not currently open.
+ */
+
+ else if (ch->ch_open_count == 0) {
+ /*
+ * Return an error when an Incoming Open
+ * response indicates the port is busy.
+ */
+
+ if (ch->ch_open_error != 0 && otype == ch->ch_otype) {
+ retval = (ch->ch_open_error <= 2) ?
+ delay_error : -ENXIO ;
+ goto unlock;
+ }
+
+ /*
+ * Fail any new Immediate open if we do not have
+ * a normal connection to the server.
+ */
+
+ if (nd->nd_state != NS_READY &&
+ otype == OTYPE_IMMEDIATE) {
+ retval = -EAGAIN;
+ goto unlock;
+ }
+
+ /*
+ * If a Realport open of the correct type has
+ * succeeded, complete the open.
+ */
+
+ if (ch->ch_state == CS_READY && ch->ch_otype == otype)
+ break;
+ }
+
+ /*
+ * Handle port already open and active as a device
+ * of same category.
+ */
+
+ else if ((ch->ch_category == category) ||
+ IS_PRINT(MINOR(tty_devnum(tty)))) {
+ /*
+ * Fail if opening the device now would
+ * violate exclusive use.
+ */
+ unf = ch->ch_tun.un_flag | ch->ch_pun.un_flag;
+
+ if ((file->f_flags & O_EXCL) || (unf & UN_EXCL)) {
+ retval = -EBUSY;
+ goto unlock;
+ }
+
+ /*
+ * If the open device is in the hangup state, all
+ * system calls fail except close().
+ */
+
+ /* TODO : check on hangup_p calls */
+
+ if (ch->ch_flag & CH_HANGUP) {
+ retval = -ENXIO;
+ goto unlock;
+ }
+
+ /*
+ * If the port is ready, and carrier is ignored
+ * or present, then complete the open.
+ */
+
+ if (ch->ch_state == CS_READY &&
+ (otype != OTYPE_INCOMING ||
+ ch->ch_flag & CH_VIRT_CD))
+ break;
+
+ wait_carrier = 1;
+ }
+
+ /*
+ * Handle port active with a different category device.
+ */
+
+ else {
+ if (otype == OTYPE_IMMEDIATE) {
+ retval = delay_error;
+ goto unlock;
+ }
+ }
+
+ /*
+ * Wait until conditions change, then take another
+ * try at the open.
+ */
+
+ ch->ch_wait_count[otype]++;
+
+ if (wait_carrier)
+ ch->ch_wait_carrier++;
+
+ /*
+ * Prepare the task to accept the wakeup, then
+ * release our locks and release control.
+ */
+
+ add_wait_queue(&ch->ch_flag_wait, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+
+ spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
+
+ /*
+ * Give up control, we'll come back if we're
+ * interrupted or are woken up.
+ */
+ schedule();
+ remove_wait_queue(&ch->ch_flag_wait, &wait);
+
+ spin_lock_irqsave(&nd->nd_lock, lock_flags);
+
+ current->state = TASK_RUNNING;
+
+ ch->ch_wait_count[otype]--;
+
+ if (wait_carrier)
+ ch->ch_wait_carrier--;
+
+ nd->nd_tx_work = 1;
+
+ if (signal_pending(current)) {
+ retval = -EINTR;
+ goto unlock;
+ }
+ } /* end for(;;) */
+
+ /*
+ * The open has succeeded. No turning back.
+ */
+ counts_were_incremented = 1;
+ un->un_open_count++;
+ ch->ch_open_count++;
+
+ /*
+ * Initialize the channel, if it's not already open.
+ */
+
+ if (ch->ch_open_count == 1) {
+ ch->ch_flag = 0;
+ ch->ch_inwait = 0;
+ ch->ch_category = category;
+ ch->ch_pscan_state = 0;
+
+ /* TODO : find out what PS-1 bug Gene was referring to */
+ /* TODO : in the following comment. */
+
+ ch->ch_send = RR_TX_START | RR_RX_START; /* PS-1 bug */
+
+ if (C_CLOCAL(tty) ||
+ ch->ch_s_mlast & DM_CD ||
+ ch->ch_digi.digi_flags & DIGI_FORCEDCD)
+ ch->ch_flag |= CH_VIRT_CD;
+ else if (OPEN_FORCES_CARRIER(category))
+ ch->ch_flag |= CH_VIRT_CD;
+
+ }
+
+ /*
+ * Initialize the unit, if it is not already open.
+ */
+
+ if (un->un_open_count == 1) {
+ /*
+ * Since all terminal options are always sticky in Linux,
+ * we don't need the UN_STICKY flag to be handled specially.
+ */
+ /* clears all the digi flags, leaves serial flags */
+ un->un_flag &= ~UN_DIGI_MASK;
+
+ if (file->f_flags & O_EXCL)
+ un->un_flag |= UN_EXCL;
+
+ /* TODO : include "session" and "pgrp" */
+
+ /*
+ * In Linux, all terminal parameters are intended to be sticky.
+ * as a result, we "remove" the code which once reset the ports
+ * to sane values.
+ */
+
+ drp_param(ch);
+
+ }
+
+ un->un_flag |= UN_INITIALIZED;
+
+ retval = 0;
+
+unlock:
+
+ spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
+
+done:
+ /*
+ * Linux does a close for every open, even failed ones!
+ */
+ if (!counts_were_incremented) {
+ un->un_open_count++;
+ ch->ch_open_count++;
+ }
+
+ if (retval)
+ dev_err(tty->dev, "tty open bad return (%i)\n", retval);
+
+ return retval;
+}
+
+
+
+
+/*
+ * dgrp_tty_close() -- close function for tty_operations
+ */
+static void dgrp_tty_close(struct tty_struct *tty, struct file *file)
+{
+ struct ch_struct *ch;
+ struct un_struct *un;
+ struct nd_struct *nd;
+ int tpos;
+ int port;
+ int err = 0;
+ int s = 0;
+ ulong waketime;
+ ulong lock_flags;
+ int sent_printer_offstr = 0;
+
+ port = PORT_NUM(MINOR(tty_devnum(tty)));
+
+ un = tty->driver_data;
+
+ if (!un)
+ return;
+
+ ch = un->un_ch;
+
+ if (!ch)
+ return;
+
+ nd = ch->ch_nd;
+
+ if (!nd)
+ return;
+
+ spin_lock_irqsave(&nd->nd_lock, lock_flags);
+
+
+ /* Used to be on channel basis, now we check on a unit basis. */
+ if (un->un_open_count != 1)
+ goto unlock;
+
+ /*
+ * OK, its the last close on the unit
+ */
+ un->un_flag |= UN_CLOSING;
+
+ /*
+ * Notify the discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+
+ /*
+ * Wait for output to drain only if this is
+ * the last close against the channel
+ */
+
+ if (ch->ch_open_count == 1) {
+ /*
+ * If its the print device, we need to ensure at all costs that
+ * the offstr will fit. If it won't, flush our tbuf.
+ */
+ if (IS_PRINT(MINOR(tty_devnum(tty))) &&
+ (((ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK) <
+ ch->ch_digi.digi_offlen))
+ ch->ch_tin = ch->ch_tout;
+
+ /*
+ * Turn off the printer. Don't bother checking to see if its
+ * IS_PRINT... Since this is the last close the flag is going
+ * to be cleared, so we MUST make sure the offstr gets inserted
+ * into tbuf.
+ */
+
+ if ((ch->ch_flag & CH_PRON) != 0) {
+ drp_wmove(ch, 0, ch->ch_digi.digi_offstr,
+ ch->ch_digi.digi_offlen);
+ ch->ch_flag &= ~CH_PRON;
+ sent_printer_offstr = 1;
+ }
+ }
+
+ /*
+ * Wait until either the output queue has drained, or we see
+ * absolutely no progress for 15 seconds.
+ */
+
+ tpos = ch->ch_s_tpos;
+
+ waketime = jiffies + 15 * HZ;
+
+ for (;;) {
+
+ /*
+ * Make sure the port still exists.
+ */
+
+ if (port >= nd->nd_chan_count) {
+ err = 1;
+ break;
+ }
+
+ if (signal_pending(current)) {
+ err = 1;
+ break;
+ }
+
+ /*
+ * If the port is idle (not opened on the server), we have
+ * no way of draining/flushing/closing the port on that server.
+ * So break out of loop.
+ */
+ if (ch->ch_state == CS_IDLE)
+ break;
+
+ nd->nd_tx_work = 1;
+
+ /*
+ * Exit if the queues for this unit are empty,
+ * and either the other unit is still open or all
+ * data has drained.
+ */
+
+ if ((un->un_tty)->ops->chars_in_buffer ?
+ ((un->un_tty)->ops->chars_in_buffer)(un->un_tty) == 0 : 1) {
+
+ /*
+ * We don't need to wait for a buffer to drain
+ * if the other unit is open.
+ */
+
+ if (ch->ch_open_count != un->un_open_count)
+ break;
+
+ /*
+ * The wait is complete when all queues are
+ * drained, and any break in progress is complete.
+ */
+
+ if (ch->ch_tin == ch->ch_tout &&
+ ch->ch_s_tin == ch->ch_s_tpos &&
+ (ch->ch_send & RR_TX_BREAK) == 0) {
+ break;
+ }
+ }
+
+ /*
+ * Flush TX data and exit the wait if NDELAY is set,
+ * or this is not a DIGI printer, and the close timeout
+ * expires.
+ */
+
+ if ((file->f_flags & (O_NDELAY | O_NONBLOCK)) ||
+ ((long)(jiffies - waketime) >= 0 &&
+ (ch->ch_digi.digi_flags & DIGI_PRINTER) == 0)) {
+
+ /*
+ * If we sent the printer off string, we cannot
+ * flush our internal buffers, or we might lose
+ * the offstr.
+ */
+ if (!sent_printer_offstr)
+ dgrp_tty_flush_buffer(tty);
+
+ tty_ldisc_flush(tty);
+ break;
+ }
+
+ /*
+ * Otherwise take a short nap.
+ */
+
+ ch->ch_flag |= CH_DRAIN;
+
+ spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
+
+ schedule_timeout_interruptible(1);
+ s = signal_pending(current);
+
+ spin_lock_irqsave(&nd->nd_lock, lock_flags);
+
+ if (s) {
+ /*
+ * If we had sent the printer off string, we now have
+ * some problems.
+ *
+ * The system won't let us sleep since we got an error
+ * back from sleep, presumably because the user did
+ * a ctrl-c...
+ * But we need to ensure that the offstr gets sent!
+ * Thus, we have to do something else besides sleeping.
+ * The plan:
+ * 1) Make this task uninterruptable.
+ * 2) Set up a timer to go off in 1 sec.
+ * 3) Act as tho we just got out of the sleep above.
+ *
+ * Thankfully, in the real world, this just
+ * never happens.
+ */
+
+ if (sent_printer_offstr) {
+ spin_unlock_irqrestore(&nd->nd_lock,
+ lock_flags);
+ drp_my_sleep(ch);
+ spin_lock_irqsave(&nd->nd_lock, lock_flags);
+ } else {
+ err = 1;
+ break;
+ }
+ }
+
+ /*
+ * Restart the wait if any progress is seen.
+ */
+
+ if (ch->ch_s_tpos != tpos) {
+ tpos = ch->ch_s_tpos;
+
+ /* TODO: this gives us timeout problems with nist ?? */
+ waketime = jiffies + 15 * HZ;
+ }
+ }
+
+ /*
+ * Close the line discipline
+ */
+
+ /* this is done in tty_io.c */
+ /* if ((un->un_tty)->ldisc.close)
+ * ((un->un_tty)->ldisc.close)(un->un_tty);
+ */
+
+ /* don't do this here */
+ /* un->un_flag = 0; */
+
+ /*
+ * Flush the receive buffer on terminal unit close only.
+ */
+
+ if (!IS_PRINT(MINOR(tty_devnum(tty))))
+ ch->ch_rout = ch->ch_rin;
+
+
+ /*
+ * Don't permit the close to happen until we get any pending
+ * sync request responses.
+ * There could be other ports depending upon the response as well.
+ *
+ * Also, don't permit the close to happen until any parameter
+ * changes have been sent out from the state machine as well.
+ * This is required because of a ditty -a race with -HUPCL
+ * We MUST make sure all channel parameters have been sent to the
+ * Portserver before sending a close.
+ */
+
+ if ((err != 1) && (ch->ch_state != CS_IDLE)) {
+ spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
+ s = wait_event_interruptible(ch->ch_flag_wait,
+ ((ch->ch_flag & (CH_WAITING_SYNC | CH_PARAM)) == 0));
+ spin_lock_irqsave(&nd->nd_lock, lock_flags);
+ }
+
+ /*
+ * Cleanup the channel if last unit open.
+ */
+
+ if (ch->ch_open_count == 1) {
+ ch->ch_flag = 0;
+ ch->ch_category = 0;
+ ch->ch_send = 0;
+ ch->ch_expect = 0;
+ ch->ch_tout = ch->ch_tin;
+ /* (un->un_tty)->device = 0; */
+
+ if (ch->ch_state == CS_READY)
+ ch->ch_state = CS_SEND_CLOSE;
+ }
+
+ /*
+ * Send the changes to the server
+ */
+ if (ch->ch_state != CS_IDLE) {
+ ch->ch_flag |= CH_PARAM;
+ wake_up_interruptible(&ch->ch_flag_wait);
+ }
+
+ nd->nd_tx_work = 1;
+ nd->nd_tx_ready = 1;
+
+unlock:
+ tty->closing = 0;
+
+ if (ch->ch_open_count <= 0)
+ dev_info(tty->dev,
+ "%s - unexpected value for ch->ch_open_count: %i\n",
+ __func__, ch->ch_open_count);
+ else
+ ch->ch_open_count--;
+
+ if (un->un_open_count <= 0)
+ dev_info(tty->dev,
+ "%s - unexpected value for un->un_open_count: %i\n",
+ __func__, un->un_open_count);
+ else
+ un->un_open_count--;
+
+ un->un_flag &= ~(UN_NORMAL_ACTIVE | UN_CALLOUT_ACTIVE | UN_CLOSING);
+ if (waitqueue_active(&un->un_close_wait))
+ wake_up_interruptible(&un->un_close_wait);
+
+ spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
+
+ return;
+
+}
+
+static void drp_wmove(struct ch_struct *ch, int from_user, void *buf, int count)
+{
+ int n;
+ int ret = 0;
+
+ ch->ch_nd->nd_tx_work = 1;
+
+ n = TBUF_MAX - ch->ch_tin;
+
+ if (count >= n) {
+ if (from_user)
+ ret = copy_from_user(ch->ch_tbuf + ch->ch_tin,
+ (void __user *) buf, n);
+ else
+ memcpy(ch->ch_tbuf + ch->ch_tin, buf, n);
+
+ buf = (char *) buf + n;
+ count -= n;
+ ch->ch_tin = 0;
+ }
+
+ if (from_user)
+ ret = copy_from_user(ch->ch_tbuf + ch->ch_tin,
+ (void __user *) buf, count);
+ else
+ memcpy(ch->ch_tbuf + ch->ch_tin, buf, count);
+
+ ch->ch_tin += count;
+}
+
+
+static int dgrp_calculate_txprint_bounds(struct ch_struct *ch, int space,
+ int *un_flag)
+{
+ clock_t tt;
+ clock_t mt;
+ unsigned short tmax = 0;
+
+ /*
+ * If the terminal device is busy, reschedule when
+ * the terminal device becomes idle.
+ */
+
+ if (ch->ch_tun.un_open_count != 0 &&
+ ch->ch_tun.un_tty->ops->chars_in_buffer &&
+ ((ch->ch_tun.un_tty->ops->chars_in_buffer)(ch->ch_tun.un_tty) != 0)) {
+ *un_flag = UN_PWAIT;
+ return 0;
+ }
+
+ /*
+ * Assure that whenever there is printer data in the output
+ * buffer, there always remains enough space after it to
+ * turn the printer off.
+ */
+ space -= ch->ch_digi.digi_offlen;
+
+ if (space <= 0) {
+ *un_flag = UN_EMPTY;
+ return 0;
+ }
+
+ /*
+ * We measure printer CPS speed by incrementing
+ * ch_cpstime by (HZ / digi_maxcps) for every
+ * character we output, restricting output so
+ * that ch_cpstime never exceeds lbolt.
+ *
+ * However if output has not been done for some
+ * time, lbolt will grow to very much larger than
+ * ch_cpstime, which would allow essentially
+ * unlimited amounts of output until ch_cpstime
+ * finally caught up. To avoid this, we adjust
+ * cps_time when necessary so the difference
+ * between lbolt and ch_cpstime never results
+ * in sending more than digi_bufsize characters.
+ *
+ * This nicely models a printer with an internal
+ * buffer of digi_bufsize characters.
+ *
+ * Get the time between lbolt and ch->ch_cpstime;
+ */
+
+ tt = jiffies - ch->ch_cpstime;
+
+ /*
+ * Compute the time required to send digi_bufsize
+ * characters.
+ */
+
+ mt = HZ * ch->ch_digi.digi_bufsize / ch->ch_digi.digi_maxcps;
+
+ /*
+ * Compute the number of characters that can be sent
+ * without violating the time constraint. If the
+ * direct calculation of this number is bigger than
+ * digi_bufsize, limit the number to digi_bufsize,
+ * and adjust cpstime to match.
+ */
+
+ if ((clock_t)(tt + HZ) > (clock_t)(mt + HZ)) {
+ tmax = ch->ch_digi.digi_bufsize;
+ ch->ch_cpstime = jiffies - mt;
+ } else {
+ tmax = ch->ch_digi.digi_maxcps * tt / HZ;
+ }
+
+ /*
+ * If the time constraint now binds, limit the transmit
+ * count accordingly, and tentatively arrange to be
+ * rescheduled based on time.
+ */
+
+ if (tmax < space) {
+ *un_flag = UN_TIME;
+ space = tmax;
+ }
+
+ /*
+ * Compute the total number of characters we can
+ * output before the total number of characters known
+ * to be in the output queue exceeds digi_maxchar.
+ */
+
+ tmax = (ch->ch_digi.digi_maxchar -
+ ((ch->ch_tin - ch->ch_tout) & TBUF_MASK) -
+ ((ch->ch_s_tin - ch->ch_s_tpos) & 0xffff));
+
+
+ /*
+ * If the digi_maxchar constraint now holds, limit
+ * the transmit count accordingly, and arrange to
+ * be rescheduled when the queue becomes empty.
+ */
+
+ if (space > tmax) {
+ *un_flag = UN_EMPTY;
+ space = tmax;
+ }
+
+ if (space <= 0)
+ *un_flag |= UN_EMPTY;
+
+ return space;
+}
+
+
+static int dgrp_tty_write(struct tty_struct *tty,
+ const unsigned char *buf,
+ int count)
+{
+ struct nd_struct *nd;
+ struct un_struct *un;
+ struct ch_struct *ch;
+ int space;
+ int n;
+ int t;
+ int sendcount;
+ int un_flag;
+ ulong lock_flags;
+
+ if (tty == NULL)
+ return 0;
+
+ un = tty->driver_data;
+ if (!un)
+ return 0;
+
+ ch = un->un_ch;
+ if (!ch)
+ return 0;
+
+ nd = ch->ch_nd;
+ if (!nd)
+ return 0;
+
+ /*
+ * Ignore the request if the channel is not ready.
+ */
+ if (ch->ch_state != CS_READY)
+ return 0;
+
+ spin_lock_irqsave(&dgrp_poll_data.poll_lock, lock_flags);
+
+ /*
+ * Ignore the request if output is blocked.
+ */
+ if ((un->un_flag & (UN_EMPTY | UN_LOW | UN_TIME | UN_PWAIT)) != 0) {
+ count = 0;
+ goto out;
+ }
+
+ /*
+ * Also ignore the request if DPA has this port open,
+ * and is flow controlled on reading more data.
+ */
+ if (nd->nd_dpa_debug && nd->nd_dpa_flag & DPA_WAIT_SPACE &&
+ nd->nd_dpa_port == MINOR(tty_devnum(ch->ch_tun.un_tty))) {
+ count = 0;
+ goto out;
+ }
+
+ /*
+ * Limit amount we will write to the amount of space
+ * available in the channel buffer.
+ */
+ sendcount = 0;
+
+ space = (ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK;
+
+ /*
+ * Handle the printer device.
+ */
+
+ un_flag = UN_LOW;
+
+ if (IS_PRINT(MINOR(tty_devnum(tty)))) {
+ clock_t tt;
+ clock_t mt;
+ unsigned short tmax = 0;
+
+ /*
+ * If the terminal device is busy, reschedule when
+ * the terminal device becomes idle.
+ */
+
+ if (ch->ch_tun.un_open_count != 0 &&
+ ((ch->ch_tun.un_tty->ops->chars_in_buffer)(ch->ch_tun.un_tty) != 0)) {
+ un->un_flag |= UN_PWAIT;
+ count = 0;
+ goto out;
+ }
+
+ /*
+ * Assure that whenever there is printer data in the output
+ * buffer, there always remains enough space after it to
+ * turn the printer off.
+ */
+ space -= ch->ch_digi.digi_offlen;
+
+ /*
+ * Output the printer on string.
+ */
+
+ if ((ch->ch_flag & CH_PRON) == 0) {
+ space -= ch->ch_digi.digi_onlen;
+
+ if (space < 0) {
+ un->un_flag |= UN_EMPTY;
+ (ch->ch_nd)->nd_tx_work = 1;
+ count = 0;
+ goto out;
+ }
+
+ drp_wmove(ch, 0, ch->ch_digi.digi_onstr,
+ ch->ch_digi.digi_onlen);
+
+ ch->ch_flag |= CH_PRON;
+ }
+
+ /*
+ * We measure printer CPS speed by incrementing
+ * ch_cpstime by (HZ / digi_maxcps) for every
+ * character we output, restricting output so
+ * that ch_cpstime never exceeds lbolt.
+ *
+ * However if output has not been done for some
+ * time, lbolt will grow to very much larger than
+ * ch_cpstime, which would allow essentially
+ * unlimited amounts of output until ch_cpstime
+ * finally caught up. To avoid this, we adjust
+ * cps_time when necessary so the difference
+ * between lbolt and ch_cpstime never results
+ * in sending more than digi_bufsize characters.
+ *
+ * This nicely models a printer with an internal
+ * buffer of digi_bufsize characters.
+ *
+ * Get the time between lbolt and ch->ch_cpstime;
+ */
+
+ tt = jiffies - ch->ch_cpstime;
+
+ /*
+ * Compute the time required to send digi_bufsize
+ * characters.
+ */
+
+ mt = HZ * ch->ch_digi.digi_bufsize / ch->ch_digi.digi_maxcps;
+
+ /*
+ * Compute the number of characters that can be sent
+ * without violating the time constraint. If the
+ * direct calculation of this number is bigger than
+ * digi_bufsize, limit the number to digi_bufsize,
+ * and adjust cpstime to match.
+ */
+
+ if ((clock_t)(tt + HZ) > (clock_t)(mt + HZ)) {
+ tmax = ch->ch_digi.digi_bufsize;
+ ch->ch_cpstime = jiffies - mt;
+ } else {
+ tmax = ch->ch_digi.digi_maxcps * tt / HZ;
+ }
+
+ /*
+ * If the time constraint now binds, limit the transmit
+ * count accordingly, and tentatively arrange to be
+ * rescheduled based on time.
+ */
+
+ if (tmax < space) {
+ space = tmax;
+ un_flag = UN_TIME;
+ }
+
+ /*
+ * Compute the total number of characters we can
+ * output before the total number of characters known
+ * to be in the output queue exceeds digi_maxchar.
+ */
+
+ tmax = (ch->ch_digi.digi_maxchar -
+ ((ch->ch_tin - ch->ch_tout) & TBUF_MASK) -
+ ((ch->ch_s_tin - ch->ch_s_tpos) & 0xffff));
+
+
+ /*
+ * If the digi_maxchar constraint now holds, limit
+ * the transmit count accordingly, and arrange to
+ * be rescheduled when the queue becomes empty.
+ */
+
+ if (space > tmax) {
+ space = tmax;
+ un_flag = UN_EMPTY;
+ }
+
+ }
+ /*
+ * Handle the terminal device.
+ */
+ else {
+
+ /*
+ * If the printer device is on, turn it off.
+ */
+
+ if ((ch->ch_flag & CH_PRON) != 0) {
+
+ space -= ch->ch_digi.digi_offlen;
+
+ drp_wmove(ch, 0, ch->ch_digi.digi_offstr,
+ ch->ch_digi.digi_offlen);
+
+ ch->ch_flag &= ~CH_PRON;
+ }
+ }
+
+ /*
+ * If space is 0 and its because the ch->tbuf
+ * is full, then Linux will handle a callback when queue
+ * space becomes available.
+ * tty_write returns count = 0
+ */
+
+ if (space <= 0) {
+ /* the linux tty_io.c handles this if we return 0 */
+ /* if (fp->flags & O_NONBLOCK) return -EAGAIN; */
+
+ un->un_flag |= UN_EMPTY;
+ (ch->ch_nd)->nd_tx_work = 1;
+ count = 0;
+ goto out;
+ }
+
+ count = min(count, space);
+
+ if (count > 0) {
+
+ un->un_tbusy++;
+
+ /*
+ * Copy the buffer contents to the ch_tbuf
+ * being careful to wrap around the circular queue
+ */
+
+ t = TBUF_MAX - ch->ch_tin;
+ n = count;
+
+ if (n >= t) {
+ memcpy(ch->ch_tbuf + ch->ch_tin, buf, t);
+ if (nd->nd_dpa_debug && nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(un->un_tty))))
+ dgrp_dpa_data(nd, 0, (char *) buf, t);
+ buf += t;
+ n -= t;
+ ch->ch_tin = 0;
+ sendcount += n;
+ }
+
+ memcpy(ch->ch_tbuf + ch->ch_tin, buf, n);
+ if (nd->nd_dpa_debug && nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(un->un_tty))))
+ dgrp_dpa_data(nd, 0, (char *) buf, n);
+ buf += n;
+ ch->ch_tin += n;
+ sendcount += n;
+
+ un->un_tbusy--;
+ (ch->ch_nd)->nd_tx_work = 1;
+ if (ch->ch_edelay != DGRP_RTIME) {
+ (ch->ch_nd)->nd_tx_ready = 1;
+ wake_up_interruptible(&nd->nd_tx_waitq);
+ }
+ }
+
+ ch->ch_txcount += count;
+
+ if (IS_PRINT(MINOR(tty_devnum(tty)))) {
+
+ /*
+ * Adjust ch_cpstime to account
+ * for the characters just output.
+ */
+
+ if (sendcount > 0) {
+ int cc = HZ * sendcount + ch->ch_cpsrem;
+
+ ch->ch_cpstime += cc / ch->ch_digi.digi_maxcps;
+ ch->ch_cpsrem = cc % ch->ch_digi.digi_maxcps;
+ }
+
+ /*
+ * If we are now waiting on time, schedule ourself
+ * back when we'll be able to send a block of
+ * digi_maxchar characters.
+ */
+
+ if ((un_flag & UN_TIME) != 0) {
+ ch->ch_waketime = (ch->ch_cpstime +
+ (ch->ch_digi.digi_maxchar * HZ /
+ ch->ch_digi.digi_maxcps));
+ }
+ }
+
+ /*
+ * If the printer unit is waiting for completion
+ * of terminal output, get him going again.
+ */
+
+ if ((ch->ch_pun.un_flag & UN_PWAIT) != 0)
+ (ch->ch_nd)->nd_tx_work = 1;
+
+out:
+ spin_unlock_irqrestore(&dgrp_poll_data.poll_lock, lock_flags);
+
+ return count;
+}
+
+
+/*
+ * Put a character into ch->ch_buf
+ *
+ * - used by the line discipline for OPOST processing
+ */
+
+static int dgrp_tty_put_char(struct tty_struct *tty, unsigned char new_char)
+{
+ struct un_struct *un;
+ struct ch_struct *ch;
+ ulong lock_flags;
+ int space;
+ int retval = 0;
+
+ if (tty == NULL)
+ return 0;
+
+ un = tty->driver_data;
+ if (!un)
+ return 0;
+
+ ch = un->un_ch;
+ if (!ch)
+ return 0;
+
+ if (ch->ch_state != CS_READY)
+ return 0;
+
+ spin_lock_irqsave(&dgrp_poll_data.poll_lock, lock_flags);
+
+
+ /*
+ * If space is 0 and its because the ch->tbuf
+ * Warn and dump the character, there isn't anything else
+ * we can do about it. David_Fries@digi.com
+ */
+
+ space = (ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK;
+
+ un->un_tbusy++;
+
+ /*
+ * Output the printer on string if device is TXPrint.
+ */
+ if (IS_PRINT(MINOR(tty_devnum(tty))) && (ch->ch_flag & CH_PRON) == 0) {
+ if (space < ch->ch_digi.digi_onlen) {
+ un->un_tbusy--;
+ goto out;
+ }
+ space -= ch->ch_digi.digi_onlen;
+ drp_wmove(ch, 0, ch->ch_digi.digi_onstr,
+ ch->ch_digi.digi_onlen);
+ ch->ch_flag |= CH_PRON;
+ }
+
+ /*
+ * Output the printer off string if device is NOT TXPrint.
+ */
+
+ if (!IS_PRINT(MINOR(tty_devnum(tty))) &&
+ ((ch->ch_flag & CH_PRON) != 0)) {
+ if (space < ch->ch_digi.digi_offlen) {
+ un->un_tbusy--;
+ goto out;
+ }
+
+ space -= ch->ch_digi.digi_offlen;
+ drp_wmove(ch, 0, ch->ch_digi.digi_offstr,
+ ch->ch_digi.digi_offlen);
+ ch->ch_flag &= ~CH_PRON;
+ }
+
+ if (!space) {
+ un->un_tbusy--;
+ goto out;
+ }
+
+ /*
+ * Copy the character to the ch_tbuf being
+ * careful to wrap around the circular queue
+ */
+ ch->ch_tbuf[ch->ch_tin] = new_char;
+ ch->ch_tin = (1 + ch->ch_tin) & TBUF_MASK;
+
+ if (IS_PRINT(MINOR(tty_devnum(tty)))) {
+
+ /*
+ * Adjust ch_cpstime to account
+ * for the character just output.
+ */
+
+ int cc = HZ + ch->ch_cpsrem;
+
+ ch->ch_cpstime += cc / ch->ch_digi.digi_maxcps;
+ ch->ch_cpsrem = cc % ch->ch_digi.digi_maxcps;
+
+ /*
+ * If we are now waiting on time, schedule ourself
+ * back when we'll be able to send a block of
+ * digi_maxchar characters.
+ */
+
+ ch->ch_waketime = (ch->ch_cpstime +
+ (ch->ch_digi.digi_maxchar * HZ /
+ ch->ch_digi.digi_maxcps));
+ }
+
+
+ un->un_tbusy--;
+ (ch->ch_nd)->nd_tx_work = 1;
+
+ retval = 1;
+out:
+ spin_unlock_irqrestore(&dgrp_poll_data.poll_lock, lock_flags);
+ return retval;
+}
+
+
+
+/*
+ * Flush TX buffer (make in == out)
+ *
+ * check tty_ioctl.c -- this is called after TCOFLUSH
+ */
+static void dgrp_tty_flush_buffer(struct tty_struct *tty)
+{
+ struct un_struct *un;
+ struct ch_struct *ch;
+
+ if (!tty)
+ return;
+ un = tty->driver_data;
+ if (!un)
+ return;
+
+ ch = un->un_ch;
+ if (!ch)
+ return;
+
+ ch->ch_tout = ch->ch_tin;
+ /* do NOT do this here! */
+ /* ch->ch_s_tpos = ch->ch_s_tin = 0; */
+
+ /* send the flush output command now */
+ ch->ch_send |= RR_TX_FLUSH;
+ (ch->ch_nd)->nd_tx_ready = 1;
+ (ch->ch_nd)->nd_tx_work = 1;
+ wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+
+ if (waitqueue_active(&tty->write_wait))
+ wake_up_interruptible(&tty->write_wait);
+
+ tty_wakeup(tty);
+
+}
+
+/*
+ * Return space available in Tx buffer
+ * count = ( ch->ch_tout - ch->ch_tin ) mod (TBUF_MAX - 1)
+ */
+static int dgrp_tty_write_room(struct tty_struct *tty)
+{
+ struct un_struct *un;
+ struct ch_struct *ch;
+ int count;
+
+ if (!tty)
+ return 0;
+
+ un = tty->driver_data;
+ if (!un)
+ return 0;
+
+ ch = un->un_ch;
+ if (!ch)
+ return 0;
+
+ count = (ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK;
+
+ /* We *MUST* check this, and return 0 if the Printer Unit cannot
+ * take any more data within its time constraints... If we don't
+ * return 0 and the printer has hit it time constraint, the ld will
+ * call us back doing a put_char, which cannot be rejected!!!
+ */
+ if (IS_PRINT(MINOR(tty_devnum(tty)))) {
+ int un_flag = 0;
+ count = dgrp_calculate_txprint_bounds(ch, count, &un_flag);
+ if (count <= 0)
+ count = 0;
+
+ ch->ch_pun.un_flag |= un_flag;
+ (ch->ch_nd)->nd_tx_work = 1;
+ }
+
+ return count;
+}
+
+/*
+ * Return number of characters that have not been transmitted yet.
+ * chars_in_buffer = ( ch->ch_tin - ch->ch_tout ) mod (TBUF_MAX - 1)
+ * + ( ch->ch_s_tin - ch->ch_s_tout ) mod (0xffff)
+ * = number of characters "in transit"
+ *
+ * Remember that sequence number math is always with a sixteen bit
+ * mask, not the TBUF_MASK.
+ */
+
+static int dgrp_tty_chars_in_buffer(struct tty_struct *tty)
+{
+ struct un_struct *un;
+ struct ch_struct *ch;
+ int count;
+ int count1;
+
+ if (!tty)
+ return 0;
+
+ un = tty->driver_data;
+ if (!un)
+ return 0;
+
+ ch = un->un_ch;
+ if (!ch)
+ return 0;
+
+ count1 = count = (ch->ch_tin - ch->ch_tout) & TBUF_MASK;
+ count += (ch->ch_s_tin - ch->ch_s_tpos) & 0xffff;
+ /* one for tbuf, one for the PS */
+
+ /*
+ * If we are busy transmitting add 1
+ */
+ count += un->un_tbusy;
+
+ return count;
+}
+
+
+/*****************************************************************************
+ *
+ * Helper applications for dgrp_tty_ioctl()
+ *
+ *****************************************************************************
+ */
+
+
+/**
+ * ch_to_tty_flags() -- convert channel flags to termio flags
+ * @ch_flag: Digi channel flags
+ * @flagtype: type of ch_flag (iflag, oflag or cflag)
+ *
+ * take the channel flags of the specified type and return the
+ * corresponding termio flag
+ */
+static tcflag_t ch_to_tty_flags(ushort ch_flag, char flagtype)
+{
+ tcflag_t retval = 0;
+
+ switch (flagtype) {
+ case 'i':
+ retval = ((ch_flag & IF_IGNBRK) ? IGNBRK : 0)
+ | ((ch_flag & IF_BRKINT) ? BRKINT : 0)
+ | ((ch_flag & IF_IGNPAR) ? IGNPAR : 0)
+ | ((ch_flag & IF_PARMRK) ? PARMRK : 0)
+ | ((ch_flag & IF_INPCK) ? INPCK : 0)
+ | ((ch_flag & IF_ISTRIP) ? ISTRIP : 0)
+ | ((ch_flag & IF_IXON) ? IXON : 0)
+ | ((ch_flag & IF_IXANY) ? IXANY : 0)
+ | ((ch_flag & IF_IXOFF) ? IXOFF : 0);
+ break;
+
+ case 'o':
+ retval = ((ch_flag & OF_OLCUC) ? OLCUC : 0)
+ | ((ch_flag & OF_ONLCR) ? ONLCR : 0)
+ | ((ch_flag & OF_OCRNL) ? OCRNL : 0)
+ | ((ch_flag & OF_ONOCR) ? ONOCR : 0)
+ | ((ch_flag & OF_ONLRET) ? ONLRET : 0)
+ /* | ((ch_flag & OF_OTAB3) ? OFILL : 0) */
+ | ((ch_flag & OF_TABDLY) ? TABDLY : 0);
+ break;
+
+ case 'c':
+ retval = ((ch_flag & CF_CSTOPB) ? CSTOPB : 0)
+ | ((ch_flag & CF_CREAD) ? CREAD : 0)
+ | ((ch_flag & CF_PARENB) ? PARENB : 0)
+ | ((ch_flag & CF_PARODD) ? PARODD : 0)
+ | ((ch_flag & CF_HUPCL) ? HUPCL : 0);
+
+ switch (ch_flag & CF_CSIZE) {
+ case CF_CS5:
+ retval |= CS5;
+ break;
+ case CF_CS6:
+ retval |= CS6;
+ break;
+ case CF_CS7:
+ retval |= CS7;
+ break;
+ case CF_CS8:
+ retval |= CS8;
+ break;
+ default:
+ retval |= CS8;
+ break;
+ }
+ break;
+ case 'x':
+ break;
+ case 'l':
+ break;
+ default:
+ return 0;
+ }
+
+ return retval;
+}
+
+
+/**
+ * tty_to_ch_flags() -- convert termio flags to digi channel flags
+ * @tty: pointer to a TTY structure holding flag to be converted
+ * @flagtype: identifies which flag (iflags, oflags, or cflags) should
+ * be converted
+ *
+ * take the termio flag of the specified type and return the
+ * corresponding Digi version of the flags
+ */
+static ushort tty_to_ch_flags(struct tty_struct *tty, char flagtype)
+{
+ ushort retval = 0;
+ tcflag_t tflag = 0;
+
+ switch (flagtype) {
+ case 'i':
+ tflag = tty->termios.c_iflag;
+ retval = (I_IGNBRK(tty) ? IF_IGNBRK : 0)
+ | (I_BRKINT(tty) ? IF_BRKINT : 0)
+ | (I_IGNPAR(tty) ? IF_IGNPAR : 0)
+ | (I_PARMRK(tty) ? IF_PARMRK : 0)
+ | (I_INPCK(tty) ? IF_INPCK : 0)
+ | (I_ISTRIP(tty) ? IF_ISTRIP : 0)
+ | (I_IXON(tty) ? IF_IXON : 0)
+ | (I_IXANY(tty) ? IF_IXANY : 0)
+ | (I_IXOFF(tty) ? IF_IXOFF : 0);
+ break;
+ case 'o':
+ tflag = tty->termios.c_oflag;
+ /*
+ * If OPOST is set, then do the post processing in the
+ * firmware by setting all the processing flags on.
+ * If ~OPOST, then make sure we are not doing any
+ * output processing!!
+ */
+ if (!O_OPOST(tty))
+ retval = 0;
+ else
+ retval = (O_OLCUC(tty) ? OF_OLCUC : 0)
+ | (O_ONLCR(tty) ? OF_ONLCR : 0)
+ | (O_OCRNL(tty) ? OF_OCRNL : 0)
+ | (O_ONOCR(tty) ? OF_ONOCR : 0)
+ | (O_ONLRET(tty) ? OF_ONLRET : 0)
+ /* | (O_OFILL(tty) ? OF_TAB3 : 0) */
+ | (O_TABDLY(tty) ? OF_TABDLY : 0);
+ break;
+ case 'c':
+ tflag = tty->termios.c_cflag;
+ retval = (C_CSTOPB(tty) ? CF_CSTOPB : 0)
+ | (C_CREAD(tty) ? CF_CREAD : 0)
+ | (C_PARENB(tty) ? CF_PARENB : 0)
+ | (C_PARODD(tty) ? CF_PARODD : 0)
+ | (C_HUPCL(tty) ? CF_HUPCL : 0);
+ switch (C_CSIZE(tty)) {
+ case CS8:
+ retval |= CF_CS8;
+ break;
+ case CS7:
+ retval |= CF_CS7;
+ break;
+ case CS6:
+ retval |= CF_CS6;
+ break;
+ case CS5:
+ retval |= CF_CS5;
+ break;
+ default:
+ retval |= CF_CS8;
+ break;
+ }
+ break;
+ case 'x':
+ break;
+ case 'l':
+ break;
+ default:
+ return 0;
+ }
+
+ return retval;
+}
+
+
+static int dgrp_tty_send_break(struct tty_struct *tty, int msec)
+{
+ struct un_struct *un;
+ struct ch_struct *ch;
+ int ret = -EIO;
+
+ if (!tty)
+ return ret;
+
+ un = tty->driver_data;
+ if (!un)
+ return ret;
+
+ ch = un->un_ch;
+ if (!ch)
+ return ret;
+
+ dgrp_send_break(ch, msec);
+ return 0;
+}
+
+
+/*
+ * This routine sends a break character out the serial port.
+ *
+ * duration is in 1/1000's of a second
+ */
+static int dgrp_send_break(struct ch_struct *ch, int msec)
+{
+ ulong x;
+
+ wait_event_interruptible(ch->ch_flag_wait,
+ ((ch->ch_flag & CH_TX_BREAK) == 0));
+ ch->ch_break_time += max(msec, 250);
+ ch->ch_send |= RR_TX_BREAK;
+ ch->ch_flag |= CH_TX_BREAK;
+ (ch->ch_nd)->nd_tx_work = 1;
+
+ x = (msec * HZ) / 1000;
+ wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+
+ return 0;
+}
+
+
+/*
+ * Return modem signals to ld.
+ */
+static int dgrp_tty_tiocmget(struct tty_struct *tty)
+{
+ unsigned int mlast;
+ struct un_struct *un = tty->driver_data;
+ struct ch_struct *ch;
+
+ if (!un)
+ return -ENODEV;
+
+ ch = un->un_ch;
+ if (!ch)
+ return -ENODEV;
+
+ mlast = ((ch->ch_s_mlast & ~(DM_RTS | DM_DTR)) |
+ (ch->ch_mout & (DM_RTS | DM_DTR)));
+
+ /* defined in /usr/include/asm/termios.h */
+ mlast = ((mlast & DM_RTS) ? TIOCM_RTS : 0)
+ | ((mlast & DM_DTR) ? TIOCM_DTR : 0)
+ | ((mlast & DM_CD) ? TIOCM_CAR : 0)
+ | ((mlast & DM_RI) ? TIOCM_RNG : 0)
+ | ((mlast & DM_DSR) ? TIOCM_DSR : 0)
+ | ((mlast & DM_CTS) ? TIOCM_CTS : 0);
+
+ return mlast;
+}
+
+
+/*
+ * Set modem lines
+ */
+static int dgrp_tty_tiocmset(struct tty_struct *tty,
+ unsigned int set, unsigned int clear)
+{
+ ulong lock_flags;
+ struct un_struct *un = tty->driver_data;
+ struct ch_struct *ch;
+
+ if (!un)
+ return -ENODEV;
+
+ ch = un->un_ch;
+ if (!ch)
+ return -ENODEV;
+
+ if (set & TIOCM_RTS)
+ ch->ch_mout |= DM_RTS;
+
+ if (set & TIOCM_DTR)
+ ch->ch_mout |= DM_DTR;
+
+ if (clear & TIOCM_RTS)
+ ch->ch_mout &= ~(DM_RTS);
+
+ if (clear & TIOCM_DTR)
+ ch->ch_mout &= ~(DM_DTR);
+
+ spin_lock_irqsave(&(ch->ch_nd)->nd_lock, lock_flags);
+ ch->ch_flag |= CH_PARAM;
+ (ch->ch_nd)->nd_tx_work = 1;
+ wake_up_interruptible(&ch->ch_flag_wait);
+
+ spin_unlock_irqrestore(&(ch->ch_nd)->nd_lock, lock_flags);
+
+ return 0;
+}
+
+
+
+/*
+ * Get current modem status
+ */
+static int get_modem_info(struct ch_struct *ch, unsigned int *value)
+{
+ unsigned int mlast;
+
+ mlast = ((ch->ch_s_mlast & ~(DM_RTS | DM_DTR)) |
+ (ch->ch_mout & (DM_RTS | DM_DTR)));
+
+ /* defined in /usr/include/asm/termios.h */
+ mlast = ((mlast & DM_RTS) ? TIOCM_RTS : 0)
+ | ((mlast & DM_DTR) ? TIOCM_DTR : 0)
+ | ((mlast & DM_CD) ? TIOCM_CAR : 0)
+ | ((mlast & DM_RI) ? TIOCM_RNG : 0)
+ | ((mlast & DM_DSR) ? TIOCM_DSR : 0)
+ | ((mlast & DM_CTS) ? TIOCM_CTS : 0);
+ put_user(mlast, (unsigned int __user *) value);
+
+ return 0;
+}
+
+/*
+ * Set modem lines
+ */
+static int set_modem_info(struct ch_struct *ch, unsigned int command,
+ unsigned int *value)
+{
+ int error;
+ unsigned int arg;
+ int mval = 0;
+ ulong lock_flags;
+
+ error = access_ok(VERIFY_READ, (void __user *) value, sizeof(int));
+ if (error == 0)
+ return -EFAULT;
+
+ get_user(arg, (unsigned int __user *) value);
+ mval |= ((arg & TIOCM_RTS) ? DM_RTS : 0)
+ | ((arg & TIOCM_DTR) ? DM_DTR : 0);
+
+ switch (command) {
+ case TIOCMBIS: /* set flags */
+ ch->ch_mout |= mval;
+ break;
+ case TIOCMBIC: /* clear flags */
+ ch->ch_mout &= ~mval;
+ break;
+ case TIOCMSET:
+ ch->ch_mout = mval;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&(ch->ch_nd)->nd_lock, lock_flags);
+
+ ch->ch_flag |= CH_PARAM;
+ (ch->ch_nd)->nd_tx_work = 1;
+ wake_up_interruptible(&ch->ch_flag_wait);
+
+ spin_unlock_irqrestore(&(ch->ch_nd)->nd_lock, lock_flags);
+
+ return 0;
+}
+
+
+/*
+ * Assign the custom baud rate to the channel structure
+ */
+static void dgrp_set_custom_speed(struct ch_struct *ch, int newrate)
+{
+ int testdiv;
+ int testrate_high;
+ int testrate_low;
+
+ int deltahigh, deltalow;
+
+ if (newrate < 0)
+ newrate = 0;
+
+ /*
+ * Since the divisor is stored in a 16-bit integer, we make sure
+ * we don't allow any rates smaller than a 16-bit integer would allow.
+ * And of course, rates above the dividend won't fly.
+ */
+ if (newrate && newrate < ((PORTSERVER_DIVIDEND / 0xFFFF) + 1))
+ newrate = ((PORTSERVER_DIVIDEND / 0xFFFF) + 1);
+ if (newrate && newrate > PORTSERVER_DIVIDEND)
+ newrate = PORTSERVER_DIVIDEND;
+
+ while (newrate > 0) {
+ testdiv = PORTSERVER_DIVIDEND / newrate;
+
+ /*
+ * If we try to figure out what rate the PortServer would use
+ * with the test divisor, it will be either equal or higher
+ * than the requested baud rate. If we then determine the
+ * rate with a divisor one higher, we will get the next lower
+ * supported rate below the requested.
+ */
+ testrate_high = PORTSERVER_DIVIDEND / testdiv;
+ testrate_low = PORTSERVER_DIVIDEND / (testdiv + 1);
+
+ /*
+ * If the rate for the requested divisor is correct, just
+ * use it and be done.
+ */
+ if (testrate_high == newrate)
+ break;
+
+ /*
+ * Otherwise, pick the rate that is closer (i.e. whichever rate
+ * has a smaller delta).
+ */
+ deltahigh = testrate_high - newrate;
+ deltalow = newrate - testrate_low;
+
+ if (deltahigh < deltalow)
+ newrate = testrate_high;
+ else
+ newrate = testrate_low;
+
+ break;
+ }
+
+ ch->ch_custom_speed = newrate;
+
+ drp_param(ch);
+
+ return;
+}
+
+
+/*
+ # dgrp_tty_digiseta()
+ *
+ * Ioctl to set the information from ditty.
+ *
+ * NOTE: DIGI_IXON, DSRPACE, DCDPACE, and DTRPACE are unsupported. JAR 990922
+ */
+static int dgrp_tty_digiseta(struct tty_struct *tty,
+ struct digi_struct *new_info)
+{
+ struct un_struct *un = tty->driver_data;
+ struct ch_struct *ch;
+
+ if (!un)
+ return -ENODEV;
+
+ ch = un->un_ch;
+ if (!ch)
+ return -ENODEV;
+
+ if (copy_from_user(&ch->ch_digi, (void __user *) new_info,
+ sizeof(struct digi_struct)))
+ return -EFAULT;
+
+ if ((ch->ch_digi.digi_flags & RTSPACE) ||
+ (ch->ch_digi.digi_flags & CTSPACE))
+ tty->termios.c_cflag |= CRTSCTS;
+ else
+ tty->termios.c_cflag &= ~CRTSCTS;
+
+ if (ch->ch_digi.digi_maxcps < 1)
+ ch->ch_digi.digi_maxcps = 1;
+
+ if (ch->ch_digi.digi_maxcps > 10000)
+ ch->ch_digi.digi_maxcps = 10000;
+
+ if (ch->ch_digi.digi_bufsize < 10)
+ ch->ch_digi.digi_bufsize = 10;
+
+ if (ch->ch_digi.digi_maxchar < 1)
+ ch->ch_digi.digi_maxchar = 1;
+
+ if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize)
+ ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize;
+
+ if (ch->ch_digi.digi_onlen > DIGI_PLEN)
+ ch->ch_digi.digi_onlen = DIGI_PLEN;
+
+ if (ch->ch_digi.digi_offlen > DIGI_PLEN)
+ ch->ch_digi.digi_offlen = DIGI_PLEN;
+
+ /* make the changes now */
+ drp_param(ch);
+
+ return 0;
+}
+
+
+
+/*
+ * dgrp_tty_digigetedelay()
+ *
+ * Ioctl to get the current edelay setting.
+ *
+ *
+ *
+ */
+static int dgrp_tty_digigetedelay(struct tty_struct *tty, int *retinfo)
+{
+ struct un_struct *un;
+ struct ch_struct *ch;
+ int tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return -EFAULT;
+
+ un = tty->driver_data;
+
+ if (!un)
+ return -ENODEV;
+
+ ch = un->un_ch;
+ if (!ch)
+ return -ENODEV;
+
+ tmp = ch->ch_edelay;
+
+ if (copy_to_user((void __user *) retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+/*
+ * dgrp_tty_digisetedelay()
+ *
+ * Ioctl to set the EDELAY setting
+ *
+ */
+static int dgrp_tty_digisetedelay(struct tty_struct *tty, int *new_info)
+{
+ struct un_struct *un;
+ struct ch_struct *ch;
+ int new_digi;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return -EFAULT;
+
+ un = tty->driver_data;
+
+ if (!un)
+ return -ENODEV;
+
+ ch = un->un_ch;
+ if (!ch)
+ return -ENODEV;
+
+ if (copy_from_user(&new_digi, (void __user *)new_info, sizeof(int)))
+ return -EFAULT;
+
+ ch->ch_edelay = new_digi;
+
+ /* make the changes now */
+ drp_param(ch);
+
+ return 0;
+}
+
+
+/*
+ * The usual assortment of ioctl's
+ *
+ * note: use tty_check_change to make sure that we are not
+ * changing the state of a terminal when we are not a process
+ * in the forground. See tty_io.c
+ * rc = tty_check_change(tty);
+ * if (rc) return rc;
+ */
+static int dgrp_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
+ unsigned long arg)
+{
+ struct un_struct *un;
+ struct ch_struct *ch;
+ int rc;
+ struct digiflow_struct dflow;
+
+ if (!tty)
+ return -ENODEV;
+
+ un = tty->driver_data;
+ if (!un)
+ return -ENODEV;
+
+ ch = un->un_ch;
+ if (!ch)
+ return -ENODEV;
+
+ switch (cmd) {
+
+ /*
+ * Here are all the standard ioctl's that we MUST implement
+ */
+
+ case TCSBRK:
+ /*
+ * TCSBRK is SVID version: non-zero arg --> no break
+ * this behaviour is exploited by tcdrain().
+ *
+ * According to POSIX.1 spec (7.2.2.1.2) breaks should be
+ * between 0.25 and 0.5 seconds
+ */
+
+ rc = tty_check_change(tty);
+ if (rc)
+ return rc;
+ tty_wait_until_sent(tty, 0);
+
+ if (!arg)
+ rc = dgrp_send_break(ch, 250); /* 1/4 second */
+
+ if (dgrp_tty_chars_in_buffer(tty) != 0)
+ return -EINTR;
+
+ return 0;
+
+ case TCSBRKP:
+ /* support for POSIX tcsendbreak()
+ *
+ * According to POSIX.1 spec (7.2.2.1.2) breaks should be
+ * between 0.25 and 0.5 seconds so we'll ask for something
+ * in the middle: 0.375 seconds.
+ */
+ rc = tty_check_change(tty);
+ if (rc)
+ return rc;
+ tty_wait_until_sent(tty, 0);
+
+ rc = dgrp_send_break(ch, arg ? arg*250 : 250);
+
+ if (dgrp_tty_chars_in_buffer(tty) != 0)
+ return -EINTR;
+ return 0;
+
+ case TIOCSBRK:
+ rc = tty_check_change(tty);
+ if (rc)
+ return rc;
+ tty_wait_until_sent(tty, 0);
+
+ /*
+ * RealPort doesn't support turning on a break unconditionally.
+ * The RealPort device will stop sending a break automatically
+ * after the specified time value that we send in.
+ */
+ rc = dgrp_send_break(ch, 250); /* 1/4 second */
+
+ if (dgrp_tty_chars_in_buffer(tty) != 0)
+ return -EINTR;
+ return 0;
+
+ case TIOCCBRK:
+ /*
+ * RealPort doesn't support turning off a break unconditionally.
+ * The RealPort device will stop sending a break automatically
+ * after the specified time value that was sent when turning on
+ * the break.
+ */
+ return 0;
+
+ case TIOCGSOFTCAR:
+ rc = access_ok(VERIFY_WRITE, (void __user *) arg,
+ sizeof(long));
+ if (rc == 0)
+ return -EFAULT;
+ put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) arg);
+ return 0;
+
+ case TIOCSSOFTCAR:
+ get_user(arg, (unsigned long __user *) arg);
+ tty->termios.c_cflag =
+ ((tty->termios.c_cflag & ~CLOCAL) |
+ (arg ? CLOCAL : 0));
+ return 0;
+
+ case TIOCMGET:
+ rc = access_ok(VERIFY_WRITE, (void __user *) arg,
+ sizeof(unsigned int));
+ if (rc == 0)
+ return -EFAULT;
+ return get_modem_info(ch, (unsigned int *) arg);
+
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ return set_modem_info(ch, cmd, (unsigned int *) arg);
+
+ /*
+ * Here are any additional ioctl's that we want to implement
+ */
+
+ case TCFLSH:
+ /*
+ * The linux tty driver doesn't have a flush
+ * input routine for the driver, assuming all backed
+ * up data is in the line disc. buffers. However,
+ * we all know that's not the case. Here, we
+ * act on the ioctl, but then lie and say we didn't
+ * so the line discipline will process the flush
+ * also.
+ */
+ rc = tty_check_change(tty);
+ if (rc)
+ return rc;
+
+ switch (arg) {
+ case TCIFLUSH:
+ case TCIOFLUSH:
+ /* only flush input if this is the only open unit */
+ if (!IS_PRINT(MINOR(tty_devnum(tty)))) {
+ ch->ch_rout = ch->ch_rin;
+ ch->ch_send |= RR_RX_FLUSH;
+ (ch->ch_nd)->nd_tx_work = 1;
+ (ch->ch_nd)->nd_tx_ready = 1;
+ wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+ }
+ if (arg == TCIFLUSH)
+ break;
+
+ case TCOFLUSH: /* flush output, or the receive buffer */
+ /*
+ * This is handled in the tty_ioctl.c code
+ * calling tty_flush_buffer
+ */
+ break;
+
+ default:
+ /* POSIX.1 says return EINVAL if we got a bad arg */
+ return -EINVAL;
+ }
+ /* pretend we didn't recognize this IOCTL */
+ return -ENOIOCTLCMD;
+
+#ifdef TIOCGETP
+ case TIOCGETP:
+#endif
+ /*****************************************
+ Linux HPUX Function
+ TCSETA TCSETA - set the termios
+ TCSETAF TCSETAF - wait for drain first, then set termios
+ TCSETAW TCSETAW - wait for drain, flush the input queue, then set termios
+ - looking at the tty_ioctl code, these command all call our
+ tty_set_termios at the driver's end, when a TCSETA* is sent,
+ it is expecting the tty to have a termio structure,
+ NOT a termios stucture. These two structures differ in size
+ and the tty_ioctl code does a conversion before processing them both.
+ - we should treat the TCSETAW TCSETAF ioctls the same, and let
+ the tty_ioctl code do the conversion stuff.
+
+ TCSETS
+ TCSETSF (none)
+ TCSETSW
+ - the associated tty structure has a termios structure.
+ *****************************************/
+
+ case TCGETS:
+ case TCGETA:
+ return -ENOIOCTLCMD;
+
+ case TCSETAW:
+ case TCSETAF:
+ case TCSETSF:
+ case TCSETSW:
+ /*
+ * The linux tty driver doesn't have a flush
+ * input routine for the driver, assuming all backed
+ * up data is in the line disc. buffers. However,
+ * we all know that's not the case. Here, we
+ * act on the ioctl, but then lie and say we didn't
+ * so the line discipline will process the flush
+ * also.
+ */
+
+ /*
+ * Also, now that we have TXPrint, we have to check
+ * if this is the TXPrint device and the terminal
+ * device is open. If so, do NOT run check_change,
+ * as the terminal device is ALWAYS the parent.
+ */
+ if (!IS_PRINT(MINOR(tty_devnum(tty))) ||
+ !ch->ch_tun.un_open_count) {
+ rc = tty_check_change(tty);
+ if (rc)
+ return rc;
+ }
+
+ /* wait for all the characters in tbuf to drain */
+ tty_wait_until_sent(tty, 0);
+
+ if ((cmd == TCSETSF) || (cmd == TCSETAF)) {
+ /* flush the contents of the rbuf queue */
+ /* TODO: check if this is print device? */
+ ch->ch_send |= RR_RX_FLUSH;
+ (ch->ch_nd)->nd_tx_ready = 1;
+ (ch->ch_nd)->nd_tx_work = 1;
+ wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+ /* do we need to do this? just to be safe! */
+ ch->ch_rout = ch->ch_rin;
+ }
+
+ /* pretend we didn't recognize this */
+ return -ENOIOCTLCMD;
+
+ case TCXONC:
+ /*
+ * The Linux Line Discipline (LD) would do this for us if we
+ * let it, but we have the special firmware options to do this
+ * the "right way" regardless of hardware or software flow
+ * control so we'll do it outselves instead of letting the LD
+ * do it.
+ */
+ rc = tty_check_change(tty);
+ if (rc)
+ return rc;
+
+ switch (arg) {
+ case TCOON:
+ dgrp_tty_start(tty);
+ return 0;
+ case TCOOFF:
+ dgrp_tty_stop(tty);
+ return 0;
+ case TCION:
+ dgrp_tty_input_start(tty);
+ return 0;
+ case TCIOFF:
+ dgrp_tty_input_stop(tty);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ case DIGI_GETA:
+ /* get information for ditty */
+ if (copy_to_user((struct digi_struct __user *) arg,
+ &ch->ch_digi, sizeof(struct digi_struct)))
+ return -EFAULT;
+ break;
+
+ case DIGI_SETAW:
+ case DIGI_SETAF:
+ /* wait for all the characters in tbuf to drain */
+ tty_wait_until_sent(tty, 0);
+
+ if (cmd == DIGI_SETAF) {
+ /* flush the contents of the rbuf queue */
+ /* send down a packet with RR_RX_FLUSH set */
+ ch->ch_send |= RR_RX_FLUSH;
+ (ch->ch_nd)->nd_tx_ready = 1;
+ (ch->ch_nd)->nd_tx_work = 1;
+ wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+ /* do we need to do this? just to be safe! */
+ ch->ch_rout = ch->ch_rin;
+ }
+
+ /* pretend we didn't recognize this */
+
+ case DIGI_SETA:
+ return dgrp_tty_digiseta(tty, (struct digi_struct *) arg);
+
+ case DIGI_SEDELAY:
+ return dgrp_tty_digisetedelay(tty, (int *) arg);
+
+ case DIGI_GEDELAY:
+ return dgrp_tty_digigetedelay(tty, (int *) arg);
+
+ case DIGI_GETFLOW:
+ case DIGI_GETAFLOW:
+ if (cmd == (DIGI_GETFLOW)) {
+ dflow.startc = tty->termios.c_cc[VSTART];
+ dflow.stopc = tty->termios.c_cc[VSTOP];
+ } else {
+ dflow.startc = ch->ch_xxon;
+ dflow.stopc = ch->ch_xxoff;
+ }
+
+ if (copy_to_user((char __user *)arg, &dflow, sizeof(dflow)))
+ return -EFAULT;
+ break;
+
+ case DIGI_SETFLOW:
+ case DIGI_SETAFLOW:
+
+ if (copy_from_user(&dflow, (char __user *)arg, sizeof(dflow)))
+ return -EFAULT;
+
+ if (cmd == (DIGI_SETFLOW)) {
+ tty->termios.c_cc[VSTART] = dflow.startc;
+ tty->termios.c_cc[VSTOP] = dflow.stopc;
+ } else {
+ ch->ch_xxon = dflow.startc;
+ ch->ch_xxoff = dflow.stopc;
+ }
+ break;
+
+ case DIGI_GETCUSTOMBAUD:
+ rc = access_ok(VERIFY_WRITE, (void __user *) arg, sizeof(int));
+ if (rc == 0)
+ return -EFAULT;
+ put_user(ch->ch_custom_speed, (unsigned int __user *) arg);
+ break;
+
+ case DIGI_SETCUSTOMBAUD:
+ {
+ int new_rate;
+
+ get_user(new_rate, (unsigned int __user *) arg);
+ dgrp_set_custom_speed(ch, new_rate);
+
+ break;
+ }
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+/*
+ * This routine allows the tty driver to be notified when
+ * the device's termios setting have changed. Note that we
+ * should be prepared to accept the case where old == NULL
+ * and try to do something rational.
+ *
+ * So we need to make sure that our copies of ch_oflag,
+ * ch_clag, and ch_iflag reflect the tty->termios flags.
+ */
+static void dgrp_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
+{
+ struct ktermios *ts;
+ struct ch_struct *ch;
+ struct un_struct *un;
+
+ /* seems silly, but we have to check all these! */
+ if (!tty)
+ return;
+
+ un = tty->driver_data;
+ if (!un)
+ return;
+
+ ts = &tty->termios;
+
+ ch = un->un_ch;
+ if (!ch)
+ return;
+
+ drp_param(ch);
+
+ /* the CLOCAL flag has just been set */
+ if (!(old->c_cflag & CLOCAL) && C_CLOCAL(tty))
+ wake_up_interruptible(&un->un_open_wait);
+}
+
+
+/*
+ * Throttle receiving data. We just set a bit and stop reading
+ * data out of the channel buffer. It will back up and the
+ * FEP will do whatever is necessary to stop the far end.
+ */
+static void dgrp_tty_throttle(struct tty_struct *tty)
+{
+ struct ch_struct *ch;
+
+ if (!tty)
+ return;
+
+ ch = ((struct un_struct *) tty->driver_data)->un_ch;
+ if (!ch)
+ return;
+
+ ch->ch_flag |= CH_RXSTOP;
+}
+
+
+static void dgrp_tty_unthrottle(struct tty_struct *tty)
+{
+ struct ch_struct *ch;
+
+ if (!tty)
+ return;
+
+ ch = ((struct un_struct *) tty->driver_data)->un_ch;
+ if (!ch)
+ return;
+
+ ch->ch_flag &= ~CH_RXSTOP;
+}
+
+/*
+ * Stop the transmitter
+ */
+static void dgrp_tty_stop(struct tty_struct *tty)
+{
+ struct ch_struct *ch;
+
+ if (!tty)
+ return;
+
+ ch = ((struct un_struct *) tty->driver_data)->un_ch;
+ if (!ch)
+ return;
+
+ ch->ch_send |= RR_TX_STOP;
+ ch->ch_send &= ~RR_TX_START;
+
+ /* make the change NOW! */
+ (ch->ch_nd)->nd_tx_ready = 1;
+ if (waitqueue_active(&(ch->ch_nd)->nd_tx_waitq))
+ wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+}
+
+/*
+ * Start the transmitter
+ */
+static void dgrp_tty_start(struct tty_struct *tty)
+{
+ struct ch_struct *ch;
+
+ if (!tty)
+ return;
+
+ ch = ((struct un_struct *) tty->driver_data)->un_ch;
+ if (!ch)
+ return;
+
+ /* TODO: don't do anything if the transmitter is not stopped */
+
+ ch->ch_send |= RR_TX_START;
+ ch->ch_send &= ~RR_TX_STOP;
+
+ /* make the change NOW! */
+ (ch->ch_nd)->nd_tx_ready = 1;
+ (ch->ch_nd)->nd_tx_work = 1;
+ if (waitqueue_active(&(ch->ch_nd)->nd_tx_waitq))
+ wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+
+}
+
+/*
+ * Stop the reciever
+ */
+static void dgrp_tty_input_stop(struct tty_struct *tty)
+{
+ struct ch_struct *ch;
+
+ if (!tty)
+ return;
+
+ ch = ((struct un_struct *) tty->driver_data)->un_ch;
+ if (!ch)
+ return;
+
+ ch->ch_send |= RR_RX_STOP;
+ ch->ch_send &= ~RR_RX_START;
+ (ch->ch_nd)->nd_tx_ready = 1;
+ if (waitqueue_active(&(ch->ch_nd)->nd_tx_waitq))
+ wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+
+}
+
+
+static void dgrp_tty_send_xchar(struct tty_struct *tty, char c)
+{
+ struct un_struct *un;
+ struct ch_struct *ch;
+
+ if (!tty)
+ return;
+
+ un = tty->driver_data;
+ if (!un)
+ return;
+
+ ch = un->un_ch;
+ if (!ch)
+ return;
+ if (c == STOP_CHAR(tty))
+ ch->ch_send |= RR_RX_STOP;
+ else if (c == START_CHAR(tty))
+ ch->ch_send |= RR_RX_START;
+
+ ch->ch_nd->nd_tx_ready = 1;
+ ch->ch_nd->nd_tx_work = 1;
+
+ return;
+}
+
+
+static void dgrp_tty_input_start(struct tty_struct *tty)
+{
+ struct ch_struct *ch;
+
+ if (!tty)
+ return;
+
+ ch = ((struct un_struct *) tty->driver_data)->un_ch;
+ if (!ch)
+ return;
+
+ ch->ch_send |= RR_RX_START;
+ ch->ch_send &= ~RR_RX_STOP;
+ (ch->ch_nd)->nd_tx_ready = 1;
+ (ch->ch_nd)->nd_tx_work = 1;
+ if (waitqueue_active(&(ch->ch_nd)->nd_tx_waitq))
+ wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+
+}
+
+
+/*
+ * Hangup the port. Like a close, but don't wait for output
+ * to drain.
+ *
+ * How do we close all the channels that are open?
+ */
+static void dgrp_tty_hangup(struct tty_struct *tty)
+{
+ struct ch_struct *ch;
+ struct nd_struct *nd;
+ struct un_struct *un;
+
+ if (!tty)
+ return;
+
+ un = tty->driver_data;
+ if (!un)
+ return;
+
+ ch = un->un_ch;
+ if (!ch)
+ return;
+
+ nd = ch->ch_nd;
+
+ if (C_HUPCL(tty)) {
+ /* LOWER DTR */
+ ch->ch_mout &= ~DM_DTR;
+ /* Don't do this here */
+ /* ch->ch_flag |= CH_HANGUP; */
+ ch->ch_nd->nd_tx_ready = 1;
+ ch->ch_nd->nd_tx_work = 1;
+ if (waitqueue_active(&ch->ch_flag_wait))
+ wake_up_interruptible(&ch->ch_flag_wait);
+ }
+
+}
+
+/************************************************************************/
+/* */
+/* TTY Initialization/Cleanup Functions */
+/* */
+/************************************************************************/
+
+/*
+ * Uninitialize the TTY portion of the supplied node. Free all
+ * memory and resources associated with this node. Do it in reverse
+ * allocation order: this might possibly result in less fragmentation
+ * of memory, though I don't know this for sure.
+ */
+void
+dgrp_tty_uninit(struct nd_struct *nd)
+{
+ char id[3];
+
+ ID_TO_CHAR(nd->nd_ID, id);
+
+ if (nd->nd_ttdriver_flags & SERIAL_TTDRV_REG) {
+ tty_unregister_driver(nd->nd_serial_ttdriver);
+
+ kfree(nd->nd_serial_ttdriver->ttys);
+ nd->nd_serial_ttdriver->ttys = NULL;
+
+ put_tty_driver(nd->nd_serial_ttdriver);
+ nd->nd_ttdriver_flags &= ~SERIAL_TTDRV_REG;
+ }
+
+ if (nd->nd_ttdriver_flags & CALLOUT_TTDRV_REG) {
+ tty_unregister_driver(nd->nd_callout_ttdriver);
+
+ kfree(nd->nd_callout_ttdriver->ttys);
+ nd->nd_callout_ttdriver->ttys = NULL;
+
+ put_tty_driver(nd->nd_callout_ttdriver);
+ nd->nd_ttdriver_flags &= ~CALLOUT_TTDRV_REG;
+ }
+
+ if (nd->nd_ttdriver_flags & XPRINT_TTDRV_REG) {
+ tty_unregister_driver(nd->nd_xprint_ttdriver);
+
+ kfree(nd->nd_xprint_ttdriver->ttys);
+ nd->nd_xprint_ttdriver->ttys = NULL;
+
+ put_tty_driver(nd->nd_xprint_ttdriver);
+ nd->nd_ttdriver_flags &= ~XPRINT_TTDRV_REG;
+ }
+}
+
+
+
+/*
+ * Initialize the TTY portion of the supplied node.
+ */
+int
+dgrp_tty_init(struct nd_struct *nd)
+{
+ char id[3];
+ int rc;
+ int i;
+
+ ID_TO_CHAR(nd->nd_ID, id);
+
+ /*
+ * Initialize the TTDRIVER structures.
+ */
+
+ nd->nd_serial_ttdriver = alloc_tty_driver(CHAN_MAX);
+ sprintf(nd->nd_serial_name, "tty_dgrp_%s_", id);
+
+ nd->nd_serial_ttdriver->owner = THIS_MODULE;
+ nd->nd_serial_ttdriver->name = nd->nd_serial_name;
+ nd->nd_serial_ttdriver->name_base = 0;
+ nd->nd_serial_ttdriver->major = 0;
+ nd->nd_serial_ttdriver->minor_start = 0;
+ nd->nd_serial_ttdriver->type = TTY_DRIVER_TYPE_SERIAL;
+ nd->nd_serial_ttdriver->subtype = SERIAL_TYPE_NORMAL;
+ nd->nd_serial_ttdriver->init_termios = DefaultTermios;
+ nd->nd_serial_ttdriver->driver_name = "dgrp";
+ nd->nd_serial_ttdriver->flags = (TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV |
+ TTY_DRIVER_HARDWARE_BREAK);
+
+ /* The kernel wants space to store pointers to tty_structs. */
+ nd->nd_serial_ttdriver->ttys =
+ kzalloc(CHAN_MAX * sizeof(struct tty_struct *), GFP_KERNEL);
+ if (!nd->nd_serial_ttdriver->ttys)
+ return -ENOMEM;
+
+ tty_set_operations(nd->nd_serial_ttdriver, &dgrp_tty_ops);
+
+ if (!(nd->nd_ttdriver_flags & SERIAL_TTDRV_REG)) {
+ /*
+ * Register tty devices
+ */
+ rc = tty_register_driver(nd->nd_serial_ttdriver);
+ if (rc < 0) {
+ /*
+ * If errno is EBUSY, this means there are no more
+ * slots available to have us auto-majored.
+ * (Which is currently supported up to 256)
+ *
+ * We can still request majors above 256,
+ * we just have to do it manually.
+ */
+ if (rc == -EBUSY) {
+ int i;
+ int max_majors = 1U << (32 - MINORBITS);
+ for (i = 256; i < max_majors; i++) {
+ nd->nd_serial_ttdriver->major = i;
+ rc = tty_register_driver(nd->nd_serial_ttdriver);
+ if (rc >= 0)
+ break;
+ }
+ /* Really fail now, since we ran out
+ * of majors to try. */
+ if (i == max_majors)
+ return rc;
+
+ } else {
+ return rc;
+ }
+ }
+ nd->nd_ttdriver_flags |= SERIAL_TTDRV_REG;
+ }
+
+ nd->nd_callout_ttdriver = alloc_tty_driver(CHAN_MAX);
+ sprintf(nd->nd_callout_name, "cu_dgrp_%s_", id);
+
+ nd->nd_callout_ttdriver->owner = THIS_MODULE;
+ nd->nd_callout_ttdriver->name = nd->nd_callout_name;
+ nd->nd_callout_ttdriver->name_base = 0;
+ nd->nd_callout_ttdriver->major = nd->nd_serial_ttdriver->major;
+ nd->nd_callout_ttdriver->minor_start = 0x40;
+ nd->nd_callout_ttdriver->type = TTY_DRIVER_TYPE_SERIAL;
+ nd->nd_callout_ttdriver->subtype = SERIAL_TYPE_CALLOUT;
+ nd->nd_callout_ttdriver->init_termios = DefaultTermios;
+ nd->nd_callout_ttdriver->driver_name = "dgrp";
+ nd->nd_callout_ttdriver->flags = (TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV |
+ TTY_DRIVER_HARDWARE_BREAK);
+
+ /* The kernel wants space to store pointers to tty_structs. */
+ nd->nd_callout_ttdriver->ttys =
+ kzalloc(CHAN_MAX * sizeof(struct tty_struct *), GFP_KERNEL);
+ if (!nd->nd_callout_ttdriver->ttys)
+ return -ENOMEM;
+
+ tty_set_operations(nd->nd_callout_ttdriver, &dgrp_tty_ops);
+
+ if (dgrp_register_cudevices) {
+ if (!(nd->nd_ttdriver_flags & CALLOUT_TTDRV_REG)) {
+ /*
+ * Register cu devices
+ */
+ rc = tty_register_driver(nd->nd_callout_ttdriver);
+ if (rc < 0)
+ return rc;
+ nd->nd_ttdriver_flags |= CALLOUT_TTDRV_REG;
+ }
+ }
+
+
+ nd->nd_xprint_ttdriver = alloc_tty_driver(CHAN_MAX);
+ sprintf(nd->nd_xprint_name, "pr_dgrp_%s_", id);
+
+ nd->nd_xprint_ttdriver->owner = THIS_MODULE;
+ nd->nd_xprint_ttdriver->name = nd->nd_xprint_name;
+ nd->nd_xprint_ttdriver->name_base = 0;
+ nd->nd_xprint_ttdriver->major = nd->nd_serial_ttdriver->major;
+ nd->nd_xprint_ttdriver->minor_start = 0x80;
+ nd->nd_xprint_ttdriver->type = TTY_DRIVER_TYPE_SERIAL;
+ nd->nd_xprint_ttdriver->subtype = SERIAL_TYPE_XPRINT;
+ nd->nd_xprint_ttdriver->init_termios = DefaultTermios;
+ nd->nd_xprint_ttdriver->driver_name = "dgrp";
+ nd->nd_xprint_ttdriver->flags = (TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV |
+ TTY_DRIVER_HARDWARE_BREAK);
+
+ /* The kernel wants space to store pointers to tty_structs. */
+ nd->nd_xprint_ttdriver->ttys =
+ kzalloc(CHAN_MAX * sizeof(struct tty_struct *), GFP_KERNEL);
+ if (!nd->nd_xprint_ttdriver->ttys)
+ return -ENOMEM;
+
+ tty_set_operations(nd->nd_xprint_ttdriver, &dgrp_tty_ops);
+
+ if (dgrp_register_prdevices) {
+ if (!(nd->nd_ttdriver_flags & XPRINT_TTDRV_REG)) {
+ /*
+ * Register transparent print devices
+ */
+ rc = tty_register_driver(nd->nd_xprint_ttdriver);
+ if (rc < 0)
+ return rc;
+ nd->nd_ttdriver_flags |= XPRINT_TTDRV_REG;
+ }
+ }
+
+ for (i = 0; i < CHAN_MAX; i++) {
+ struct ch_struct *ch = nd->nd_chan + i;
+
+ ch->ch_nd = nd;
+ ch->ch_digi = digi_init;
+ ch->ch_edelay = 100;
+ ch->ch_custom_speed = 0;
+ ch->ch_portnum = i;
+ ch->ch_tun.un_ch = ch;
+ ch->ch_pun.un_ch = ch;
+ ch->ch_tun.un_type = SERIAL_TYPE_NORMAL;
+ ch->ch_pun.un_type = SERIAL_TYPE_XPRINT;
+
+ init_waitqueue_head(&(ch->ch_flag_wait));
+ init_waitqueue_head(&(ch->ch_sleep));
+
+ init_waitqueue_head(&(ch->ch_tun.un_open_wait));
+ init_waitqueue_head(&(ch->ch_tun.un_close_wait));
+
+ init_waitqueue_head(&(ch->ch_pun.un_open_wait));
+ init_waitqueue_head(&(ch->ch_pun.un_close_wait));
+ tty_port_init(&ch->port);
+ tty_port_init(&ch->port);
+ }
+ return 0;
+}
diff --git a/drivers/staging/dgrp/digirp.h b/drivers/staging/dgrp/digirp.h
new file mode 100644
index 000000000000..33c1394fade7
--- /dev/null
+++ b/drivers/staging/dgrp/digirp.h
@@ -0,0 +1,129 @@
+/************************************************************************
+ * HP-UX Realport Daemon interface file.
+ *
+ * Copyright (C) 1998, by Digi International. All Rights Reserved.
+ ************************************************************************/
+
+#ifndef _DIGIDRP_H
+#define _DIGIDRP_H
+
+/************************************************************************
+ * This file contains defines for the ioctl() interface to
+ * the realport driver. This ioctl() interface is used by the
+ * daemon to set speed setup parameters honored by the driver.
+ ************************************************************************/
+
+struct link_struct {
+ int lk_fast_rate; /* Fast line rate to be used
+ when the delay is less-equal
+ to lk_fast_delay */
+
+ int lk_fast_delay; /* Fast line rate delay in
+ milliseconds */
+
+ int lk_slow_rate; /* Slow line rate to be used when
+ the delay is greater-equal
+ to lk_slow_delay */
+
+ int lk_slow_delay; /* Slow line rate delay in
+ milliseconds */
+
+ int lk_header_size; /* Estimated packet header size
+ when sent across the slowest
+ link. */
+};
+
+#define DIGI_GETLINK _IOW('e', 103, struct link_struct) /* Get link parameters */
+#define DIGI_SETLINK _IOW('e', 104, struct link_struct) /* Set link parameters */
+
+
+/************************************************************************
+ * This module provides application access to special Digi
+ * serial line enhancements which are not standard UNIX(tm) features.
+ ************************************************************************/
+
+struct digiflow_struct {
+ unsigned char startc; /* flow cntl start char */
+ unsigned char stopc; /* flow cntl stop char */
+};
+
+/************************************************************************
+ * Values for digi_flags
+ ************************************************************************/
+#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */
+#define DIGI_FAST 0x0002 /* Fast baud rates */
+#define RTSPACE 0x0004 /* RTS input flow control */
+#define CTSPACE 0x0008 /* CTS output flow control */
+#define DSRPACE 0x0010 /* DSR output flow control */
+#define DCDPACE 0x0020 /* DCD output flow control */
+#define DTRPACE 0x0040 /* DTR input flow control */
+#define DIGI_COOK 0x0080 /* Cooked processing done in FEP */
+#define DIGI_FORCEDCD 0x0100 /* Force carrier */
+#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */
+#define DIGI_AIXON 0x0400 /* Aux flow control in fep */
+#define DIGI_PRINTER 0x0800 /* Hold port open for flow cntrl */
+#define DIGI_PP_INPUT 0x1000 /* Change parallel port to input */
+#define DIGI_422 0x4000 /* Change parallel port to input */
+#define DIGI_RTS_TOGGLE 0x8000 /* Support RTS Toggle */
+
+
+/************************************************************************
+ * Values associated with transparent print
+ ************************************************************************/
+#define DIGI_PLEN 8 /* String length */
+#define DIGI_TSIZ 10 /* Terminal string len */
+
+
+/************************************************************************
+ * Structure used with ioctl commands for DIGI parameters.
+ ************************************************************************/
+struct digi_struct {
+ unsigned short digi_flags; /* Flags (see above) */
+ unsigned short digi_maxcps; /* Max printer CPS */
+ unsigned short digi_maxchar; /* Max chars in print queue */
+ unsigned short digi_bufsize; /* Buffer size */
+ unsigned char digi_onlen; /* Length of ON string */
+ unsigned char digi_offlen; /* Length of OFF string */
+ char digi_onstr[DIGI_PLEN]; /* Printer on string */
+ char digi_offstr[DIGI_PLEN]; /* Printer off string */
+ char digi_term[DIGI_TSIZ]; /* terminal string */
+};
+
+/************************************************************************
+ * Ioctl command arguments for DIGI parameters.
+ ************************************************************************/
+/* Read params */
+#define DIGI_GETA _IOR('e', 94, struct digi_struct)
+
+/* Set params */
+#define DIGI_SETA _IOW('e', 95, struct digi_struct)
+
+/* Drain & set params */
+#define DIGI_SETAW _IOW('e', 96, struct digi_struct)
+
+/* Drain, flush & set params */
+#define DIGI_SETAF _IOW('e', 97, struct digi_struct)
+
+/* Get startc/stopc flow control characters */
+#define DIGI_GETFLOW _IOR('e', 99, struct digiflow_struct)
+
+/* Set startc/stopc flow control characters */
+#define DIGI_SETFLOW _IOW('e', 100, struct digiflow_struct)
+
+/* Get Aux. startc/stopc flow control chars */
+#define DIGI_GETAFLOW _IOR('e', 101, struct digiflow_struct)
+
+/* Set Aux. startc/stopc flow control chars */
+#define DIGI_SETAFLOW _IOW('e', 102, struct digiflow_struct)
+
+/* Set integer baud rate */
+#define DIGI_SETCUSTOMBAUD _IOW('e', 106, int)
+
+/* Get integer baud rate */
+#define DIGI_GETCUSTOMBAUD _IOR('e', 107, int)
+
+#define DIGI_GEDELAY _IOR('d', 246, int) /* Get edelay */
+#define DIGI_SEDELAY _IOW('d', 247, int) /* Get edelay */
+
+
+#endif /* _DIGIDRP_H */
diff --git a/drivers/staging/dgrp/drp.h b/drivers/staging/dgrp/drp.h
new file mode 100644
index 000000000000..84a1e7be4899
--- /dev/null
+++ b/drivers/staging/dgrp/drp.h
@@ -0,0 +1,693 @@
+/*
+ *
+ * Copyright 1999 Digi International (www.digi.com)
+ * Gene Olson <gene at digi dot com>
+ * James Puzzo <jamesp at digi dot com>
+ * Scott Kilau <scottk at digi dot com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ */
+
+/************************************************************************
+ * Master include file for Linux Realport Driver.
+ ************************************************************************/
+
+#ifndef __DRP_H
+#define __DRP_H
+
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/semaphore.h>
+#include <linux/tty.h>
+
+
+#include "digirp.h"
+
+/************************************************************************
+ * Tuning parameters.
+ ************************************************************************/
+
+#define CHAN_MAX 64 /* Max # ports per server */
+
+#define SEQ_MAX 128 /* Max # transmit sequences (2^n) */
+#define SEQ_MASK (SEQ_MAX-1) /* Sequence buffer modulus mask */
+
+#define TBUF_MAX 4096 /* Size of transmit buffer (2^n) */
+#define RBUF_MAX 4096 /* Size of receive buffer (2^n) */
+
+#define TBUF_MASK (TBUF_MAX-1) /* Transmit buffer modulus mask */
+#define RBUF_MASK (RBUF_MAX-1) /* Receive buffer modulus mask */
+
+#define TBUF_LOW 1000 /* Transmit low water mark */
+
+#define UIO_BASE 1000 /* Base for write operations */
+#define UIO_MIN 2000 /* Minimum size application buffer */
+#define UIO_MAX 8100 /* Unix I/O buffer size */
+
+#define MON_MAX 65536 /* Monitor buffer size (2^n) */
+#define MON_MASK (MON_MAX-1) /* Monitor wrap mask */
+
+#define DPA_MAX 65536 /* DPA buffer size (2^n) */
+#define DPA_MASK (DPA_MAX-1) /* DPA wrap mask */
+#define DPA_HIGH_WATER 58000 /* Enforce flow control when
+ * over this amount
+ */
+
+#define IDLE_MAX (20 * HZ) /* Max TCP link idle time */
+
+#define MAX_DESC_LEN 100 /* Maximum length of stored PS
+ * description
+ */
+
+#define WRITEBUFLEN ((4096) + 4) /* 4 extra for alignment play space */
+
+#define VPDSIZE 512
+
+/************************************************************************
+ * Minor device decoding conventions.
+ ************************************************************************
+ *
+ * For Linux, the net and mon devices are handled via "proc", so we
+ * only have to mux the "tty" devices. Since every PortServer will
+ * have an individual major number, the PortServer number does not
+ * need to be encoded, and in fact, does not need to exist.
+ *
+ */
+
+/*
+ * Port device decoding conventions:
+ *
+ * Device 00 - 3f 64 dial-in modem devices. (tty)
+ * Device 40 - 7f 64 dial-out tty devices. (cu)
+ * Device 80 - bf 64 dial-out printer devices.
+ *
+ * IS_PRINT(dev) This is a printer device.
+ *
+ * OPEN_CATEGORY(dev) Specifies the device category. No two
+ * devices of different categories may be open
+ * at the same time.
+ *
+ * The following require the category returned by OPEN_CATEGORY().
+ *
+ * OPEN_WAIT_AVAIL(cat) Waits on open until the device becomes
+ * available. Fails if NDELAY specified.
+ *
+ * OPEN_WAIT_CARRIER(cat) Waits on open if carrier is not present.
+ * Succeeds if NDELAY is given.
+ *
+ * OPEN_FORCES_CARRIER(cat) Carrier is forced high on open.
+ *
+ */
+
+#define PORT_NUM(dev) ((dev) & 0x3f)
+
+#define OPEN_CATEGORY(dev) ((((dev) & 0x80) & 0x40))
+#define IS_PRINT(dev) (((dev) & 0xff) >= 0x80)
+
+#define OPEN_WAIT_AVAIL(cat) (((cat) & 0x40) == 0x000)
+#define OPEN_WAIT_CARRIER(cat) (((cat) & 0x40) == 0x000)
+#define OPEN_FORCES_CARRIER(cat) (((cat) & 0x40) != 0x000)
+
+
+/************************************************************************
+ * Modem signal defines for 16450/16550 compatible FEP.
+ * set in ch_mout, ch_mflow, ch_mlast etc
+ ************************************************************************/
+
+/* TODO : Re-verify that these modem signal definitions are correct */
+
+#define DM_DTR 0x01
+#define DM_RTS 0x02
+#define DM_RTS_TOGGLE 0x04
+
+#define DM_OUT1 0x04
+#define DM_OUT2 0x08
+
+#define DM_CTS 0x10
+#define DM_DSR 0x20
+#define DM_RI 0x40
+#define DM_CD 0x80 /* This is the DCD flag */
+
+
+/************************************************************************
+ * Realport Event Flags.
+ ************************************************************************/
+
+#define EV_OPU 0x0001 /* Ouput paused by client */
+#define EV_OPS 0x0002 /* Output paused by XOFF */
+#define EV_OPX 0x0004 /* Output paused by XXOFF */
+#define EV_OPH 0x0008 /* Output paused by MFLOW */
+#define EV_IPU 0x0010 /* Input paused by client */
+#define EV_IPS 0x0020 /* Input paused by hi/low water */
+#define EV_TXB 0x0040 /* Transmit break pending */
+#define EV_TXI 0x0080 /* Transmit immediate pending */
+#define EV_TXF 0x0100 /* Transmit flow control pending */
+#define EV_RXB 0x0200 /* Break received */
+
+
+/************************************************************************
+ * Realport CFLAGS.
+ ************************************************************************/
+
+#define CF_CS5 0x0000 /* 5 bit characters */
+#define CF_CS6 0x0010 /* 6 bit characters */
+#define CF_CS7 0x0020 /* 7 bit characters */
+#define CF_CS8 0x0030 /* 8 bit characters */
+#define CF_CSIZE 0x0030 /* Character size */
+#define CF_CSTOPB 0x0040 /* Two stop bits */
+#define CF_CREAD 0x0080 /* Enable receiver */
+#define CF_PARENB 0x0100 /* Enable parity */
+#define CF_PARODD 0x0200 /* Odd parity */
+#define CF_HUPCL 0x0400 /* Drop DTR on close */
+
+
+/************************************************************************
+ * Realport XFLAGS.
+ ************************************************************************/
+
+#define XF_XPAR 0x0001 /* Enable Mark/Space Parity */
+#define XF_XMODEM 0x0002 /* Enable in-band modem signalling */
+#define XF_XCASE 0x0004 /* Convert special characters */
+#define XF_XEDATA 0x0008 /* Error data in stream */
+#define XF_XTOSS 0x0010 /* Toss IXANY characters */
+#define XF_XIXON 0x0020 /* xxon/xxoff enable */
+
+
+/************************************************************************
+ * Realport IFLAGS.
+ ************************************************************************/
+
+#define IF_IGNBRK 0x0001 /* Ignore input break */
+#define IF_BRKINT 0x0002 /* Break interrupt */
+#define IF_IGNPAR 0x0004 /* Ignore error characters */
+#define IF_PARMRK 0x0008 /* Error chars marked with 0xff */
+#define IF_INPCK 0x0010 /* Input parity checking enabled */
+#define IF_ISTRIP 0x0020 /* Input chars masked with 0x7F */
+#define IF_IXON 0x0400 /* Output software flow control */
+#define IF_IXANY 0x0800 /* Restart output on any char */
+#define IF_IXOFF 0x1000 /* Input software flow control */
+#define IF_DOSMODE 0x8000 /* 16450-compatible errors */
+
+
+/************************************************************************
+ * Realport OFLAGS.
+ ************************************************************************/
+
+#define OF_OLCUC 0x0002 /* Map lower to upper case */
+#define OF_ONLCR 0x0004 /* Map NL to CR-NL */
+#define OF_OCRNL 0x0008 /* Map CR to NL */
+#define OF_ONOCR 0x0010 /* No CR output at column 0 */
+#define OF_ONLRET 0x0020 /* Assume NL does NL/CR */
+#define OF_TAB3 0x1800 /* Tabs expand to 8 spaces */
+#define OF_TABDLY 0x1800 /* Tab delay */
+
+/************************************************************************
+ * Unit flag definitions for un_flag.
+ ************************************************************************/
+
+/* These are the DIGI unit flags */
+#define UN_EXCL 0x00010000 /* Exclusive open */
+#define UN_STICKY 0x00020000 /* TTY Settings are now sticky */
+#define UN_BUSY 0x00040000 /* Some work this channel */
+#define UN_PWAIT 0x00080000 /* Printer waiting for terminal */
+#define UN_TIME 0x00100000 /* Waiting on time */
+#define UN_EMPTY 0x00200000 /* Waiting output queue empty */
+#define UN_LOW 0x00400000 /* Waiting output low water */
+#define UN_DIGI_MASK 0x00FF0000 /* Waiting output low water */
+
+/*
+ * Definitions for async_struct (and serial_struct) flags field
+ *
+ * these are the ASYNC flags copied from serial.h
+ *
+ */
+#define UN_HUP_NOTIFY 0x0001 /* Notify getty on hangups and
+ * closes on the callout port
+ */
+#define UN_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
+#define UN_SAK 0x0004 /* Secure Attention Key (Orange book) */
+#define UN_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define UN_SPD_MASK 0x0030
+#define UN_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
+#define UN_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
+#define UN_SPD_CUST 0x0030 /* Use user-specified divisor */
+
+#define UN_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
+#define UN_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
+
+#define UN_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define UN_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
+#define UN_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
+
+#define UN_FLAGS 0x0FFF /* Possible legal async flags */
+#define UN_USR_MASK 0x0430 /* Legal flags that non-privileged
+ * users can set or reset
+ */
+
+#define UN_INITIALIZED 0x80000000 /* Serial port was initialized */
+#define UN_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
+#define UN_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
+#define UN_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
+#define UN_CLOSING 0x08000000 /* Serial port is closing */
+#define UN_CTS_FLOW 0x04000000 /* Do CTS flow control */
+#define UN_CHECK_CD 0x02000000 /* i.e., CLOCAL */
+#define UN_SHARE_IRQ 0x01000000 /* for multifunction cards */
+
+
+/************************************************************************
+ * Structure for terminal or printer unit. struct un_struct
+ *
+ * Note that in some places the code assumes the "tty_t" is placed
+ * first in the structure.
+ ************************************************************************/
+
+struct un_struct {
+ struct tty_struct *un_tty; /* System TTY struct */
+ struct ch_struct *un_ch; /* Associated channel */
+
+ ushort un_open_count; /* Successful open count */
+ int un_flag; /* Unit flags */
+ ushort un_tbusy; /* Busy transmit count */
+
+ wait_queue_head_t un_open_wait;
+ wait_queue_head_t un_close_wait;
+ ushort un_type;
+ struct device *un_sysfs;
+};
+
+
+/************************************************************************
+ * Channel State Numbers for ch_state.
+ ************************************************************************/
+
+/*
+ * The ordering is important.
+ *
+ * state <= CS_WAIT_CANCEL implies the channel is definitely closed.
+ *
+ * state >= CS_WAIT_FAIL implies the channel is definitely open.
+ *
+ * state >= CS_READY implies data is allowed on the channel.
+ */
+
+enum dgrp_ch_state_t {
+ CS_IDLE = 0, /* Channel is idle */
+ CS_WAIT_OPEN = 1, /* Waiting for Immediate Open Resp */
+ CS_WAIT_CANCEL = 2, /* Waiting for Per/Incom Cancel Resp */
+ CS_WAIT_FAIL = 3, /* Waiting for Immed Open Failure */
+ CS_SEND_QUERY = 4, /* Ready to send Port Query */
+ CS_WAIT_QUERY = 5, /* Waiting for Port Query Response */
+ CS_READY = 6, /* Ready to accept commands and data */
+ CS_SEND_CLOSE = 7, /* Ready to send Close Request */
+ CS_WAIT_CLOSE = 8 /* Waiting for Close Response */
+};
+
+/************************************************************************
+ * Device flag definitions for ch_flag.
+ ************************************************************************/
+
+/*
+ * Note that the state of the two carrier based flags is key. When
+ * we check for carrier state transitions, we look at the current
+ * physical state of the DCD line and compare it with PHYS_CD (which
+ * was the state the last time we checked), and we also determine
+ * a new virtual state (composite of the physical state, FORCEDCD,
+ * CLOCAL, etc.) and compare it with VIRT_CD.
+ *
+ * VIRTUAL transitions high will have the side effect of waking blocked
+ * opens.
+ *
+ * PHYSICAL transitions low will cause hangups to occur _IF_ the virtual
+ * state is also low. We DON'T want to hangup on a PURE virtual drop.
+ */
+
+#define CH_HANGUP 0x00002 /* Server port ready to close */
+
+#define CH_VIRT_CD 0x00004 /* Carrier was virtually present */
+#define CH_PHYS_CD 0x00008 /* Carrier was physically present */
+
+#define CH_CLOCAL 0x00010 /* CLOCAL set in cflags */
+#define CH_BAUD0 0x00020 /* Baud rate zero hangup */
+
+#define CH_FAST_READ 0x00040 /* Fast reads are enabled */
+#define CH_FAST_WRITE 0x00080 /* Fast writes are enabled */
+
+#define CH_PRON 0x00100 /* Printer on string active */
+#define CH_RX_FLUSH 0x00200 /* Flushing receive data */
+#define CH_LOW 0x00400 /* Thread waiting for LOW water */
+#define CH_EMPTY 0x00800 /* Thread waiting for EMPTY */
+#define CH_DRAIN 0x01000 /* Close is waiting to drain */
+#define CH_INPUT 0x02000 /* Thread waiting for INPUT */
+#define CH_RXSTOP 0x04000 /* Stop output to ldisc */
+#define CH_PARAM 0x08000 /* A parameter was updated */
+#define CH_WAITING_SYNC 0x10000 /* A pending sync was assigned
+ * to this port.
+ */
+#define CH_PORT_GONE 0x20000 /* Port has disappeared */
+#define CH_TX_BREAK 0x40000 /* TX Break to be sent,
+ * but has not yet.
+ */
+
+/************************************************************************
+ * Types of Open Requests for ch_otype.
+ ************************************************************************/
+
+#define OTYPE_IMMEDIATE 0 /* Immediate Open */
+#define OTYPE_PERSISTENT 1 /* Persistent Open */
+#define OTYPE_INCOMING 2 /* Incoming Open */
+
+
+/************************************************************************
+ * Request/Response flags.
+ ************************************************************************/
+
+#define RR_SEQUENCE 0x0001 /* Get server RLAST, TIN */
+#define RR_STATUS 0x0002 /* Get server MINT, EINT */
+#define RR_BUFFER 0x0004 /* Get server RSIZE, TSIZE */
+#define RR_CAPABILITY 0x0008 /* Get server port capabilities */
+
+#define RR_TX_FLUSH 0x0040 /* Flush output buffers */
+#define RR_RX_FLUSH 0x0080 /* Flush input buffers */
+
+#define RR_TX_STOP 0x0100 /* Pause output */
+#define RR_RX_STOP 0x0200 /* Pause input */
+#define RR_TX_START 0x0400 /* Start output */
+#define RR_RX_START 0x0800 /* Start input */
+
+#define RR_TX_BREAK 0x1000 /* Send BREAK */
+#define RR_TX_ICHAR 0x2000 /* Send character immediate */
+
+
+/************************************************************************
+ * Channel information structure. struct ch_struct
+ ************************************************************************/
+
+struct ch_struct {
+ struct digi_struct ch_digi; /* Digi variables */
+ int ch_edelay; /* Digi edelay */
+
+ struct tty_port port;
+ struct un_struct ch_tun; /* Terminal unit info */
+ struct un_struct ch_pun; /* Printer unit info */
+
+ struct nd_struct *ch_nd; /* Node pointer */
+ u8 *ch_tbuf; /* Local Transmit Buffer */
+ u8 *ch_rbuf; /* Local Receive Buffer */
+ ulong ch_cpstime; /* Printer CPS time */
+ ulong ch_waketime; /* Printer wake time */
+
+ ulong ch_flag; /* CH_* flags */
+
+ enum dgrp_ch_state_t ch_state; /* CS_* Protocol state */
+ ushort ch_send; /* Bit vector of RR_* requests */
+ ushort ch_expect; /* Bit vector of RR_* responses */
+ ushort ch_wait_carrier; /* Thread count waiting for carrier */
+ ushort ch_wait_count[3]; /* Thread count waiting by otype */
+
+ ushort ch_portnum; /* Port number */
+ ushort ch_open_count; /* Successful open count */
+ ushort ch_category; /* Device category */
+ ushort ch_open_error; /* Last open error number */
+ ushort ch_break_time; /* Pending break request time */
+ ushort ch_cpsrem; /* Printer CPS remainder */
+ ushort ch_ocook; /* Realport fastcook oflags */
+ ushort ch_inwait; /* Thread count in CLIST input */
+
+ ushort ch_tin; /* Local transmit buffer in ptr */
+ ushort ch_tout; /* Local transmit buffer out ptr */
+ ushort ch_s_tin; /* Realport TIN */
+ ushort ch_s_tpos; /* Realport TPOS */
+ ushort ch_s_tsize; /* Realport TSIZE */
+ ushort ch_s_treq; /* Realport TREQ */
+ ushort ch_s_elast; /* Realport ELAST */
+
+ ushort ch_rin; /* Local receive buffer in ptr */
+ ushort ch_rout; /* Local receive buffer out ptr */
+ ushort ch_s_rin; /* Realport RIN */
+ /* David Fries 7-13-2001, ch_s_rin should be renamed ch_s_rout because
+ * the variable we want to represent is the PortServer's ROUT, which is
+ * the sequence number for the next byte the PortServer will send us.
+ * RIN is the sequence number for the next byte the PortServer will
+ * receive from the uart. The port server will send data as long as
+ * ROUT is less than RWIN. What would happen is the port is opened, it
+ * receives data, it gives the value of RIN, we set the RWIN to
+ * RIN+RBUF_MAX-1, it sends us RWIN-ROUT bytes which overflows. ROUT
+ * is set to zero when the port is opened, so we start at zero and
+ * count up as data is received.
+ */
+ ushort ch_s_rwin; /* Realport RWIN */
+ ushort ch_s_rsize; /* Realport RSIZE */
+
+ ushort ch_tmax; /* Local TMAX */
+ ushort ch_ttime; /* Local TTIME */
+ ushort ch_rmax; /* Local RMAX */
+ ushort ch_rtime; /* Local RTIME */
+ ushort ch_rlow; /* Local RLOW */
+ ushort ch_rhigh; /* Local RHIGH */
+
+ ushort ch_s_tmax; /* Realport TMAX */
+ ushort ch_s_ttime; /* Realport TTIME */
+ ushort ch_s_rmax; /* Realport RMAX */
+ ushort ch_s_rtime; /* Realport RTIME */
+ ushort ch_s_rlow; /* Realport RLOW */
+ ushort ch_s_rhigh; /* Realport RHIGH */
+
+ ushort ch_brate; /* Local baud rate */
+ ushort ch_cflag; /* Local tty cflags */
+ ushort ch_iflag; /* Local tty iflags */
+ ushort ch_oflag; /* Local tty oflags */
+ ushort ch_xflag; /* Local tty xflags */
+
+ ushort ch_s_brate; /* Realport BRATE */
+ ushort ch_s_cflag; /* Realport CFLAG */
+ ushort ch_s_iflag; /* Realport IFLAG */
+ ushort ch_s_oflag; /* Realport OFLAG */
+ ushort ch_s_xflag; /* Realport XFLAG */
+
+ u8 ch_otype; /* Open request type */
+ u8 ch_pscan_savechar; /* Last character read by parity scan */
+ u8 ch_pscan_state; /* PScan State based on last 2 chars */
+ u8 ch_otype_waiting; /* Type of open pending in server */
+ u8 ch_flush_seq; /* Receive flush end sequence */
+ u8 ch_s_mlast; /* Realport MLAST */
+
+ u8 ch_mout; /* Local MOUT */
+ u8 ch_mflow; /* Local MFLOW */
+ u8 ch_mctrl; /* Local MCTRL */
+ u8 ch_xon; /* Local XON */
+ u8 ch_xoff; /* Local XOFF */
+ u8 ch_lnext; /* Local LNEXT */
+ u8 ch_xxon; /* Local XXON */
+ u8 ch_xxoff; /* Local XXOFF */
+
+ u8 ch_s_mout; /* Realport MOUT */
+ u8 ch_s_mflow; /* Realport MFLOW */
+ u8 ch_s_mctrl; /* Realport MCTRL */
+ u8 ch_s_xon; /* Realport XON */
+ u8 ch_s_xoff; /* Realport XOFF */
+ u8 ch_s_lnext; /* Realport LNEXT */
+ u8 ch_s_xxon; /* Realport XXON */
+ u8 ch_s_xxoff; /* Realport XXOFF */
+
+ wait_queue_head_t ch_flag_wait; /* Wait queue for ch_flag changes */
+ wait_queue_head_t ch_sleep; /* Wait queue for my_sleep() */
+
+ int ch_custom_speed; /* Realport custom speed */
+ int ch_txcount; /* Running TX count */
+ int ch_rxcount; /* Running RX count */
+};
+
+
+/************************************************************************
+ * Node State definitions.
+ ************************************************************************/
+
+enum dgrp_nd_state_t {
+ NS_CLOSED = 0, /* Network device is closed */
+ NS_IDLE = 1, /* Network connection inactive */
+ NS_SEND_QUERY = 2, /* Send server query */
+ NS_WAIT_QUERY = 3, /* Wait for query response */
+ NS_READY = 4, /* Network ready */
+ NS_SEND_ERROR = 5 /* Must send error hangup */
+};
+
+#define ND_STATE_STR(x) \
+ ((x) == NS_CLOSED ? "CLOSED" : \
+ ((x) == NS_IDLE ? "IDLE" : \
+ ((x) == NS_SEND_QUERY ? "SEND_QUERY" : \
+ ((x) == NS_WAIT_QUERY ? "WAIT_QUERY" : \
+ ((x) == NS_READY ? "READY" : \
+ ((x) == NS_SEND_ERROR ? "SEND_ERROR" : "UNKNOWN"))))))
+
+/************************************************************************
+ * Node Flag definitions.
+ ************************************************************************/
+
+#define ND_SELECT 0x0001 /* Multiple net read selects */
+#define ND_DEB_WAIT 0x0002 /* Debug Device waiting */
+
+
+/************************************************************************
+ * Monitoring flag definitions.
+ ************************************************************************/
+
+#define MON_WAIT_DATA 0x0001 /* Waiting for buffer data */
+#define MON_WAIT_SPACE 0x0002 /* Waiting for buffer space */
+
+/************************************************************************
+ * DPA flag definitions.
+ ************************************************************************/
+
+#define DPA_WAIT_DATA 0x0001 /* Waiting for buffer data */
+#define DPA_WAIT_SPACE 0x0002 /* Waiting for buffer space */
+
+
+/************************************************************************
+ * Definitions taken from Realport Dump.
+ ************************************************************************/
+
+#define RPDUMP_MAGIC "Digi-RealPort-1.0"
+
+#define RPDUMP_MESSAGE 0xE2 /* Descriptive message */
+#define RPDUMP_RESET 0xE7 /* Connection reset */
+#define RPDUMP_CLIENT 0xE8 /* Client data */
+#define RPDUMP_SERVER 0xE9 /* Server data */
+
+
+/************************************************************************
+ * Node request/response definitions.
+ ************************************************************************/
+
+#define NR_ECHO 0x0001 /* Server echo packet */
+#define NR_IDENT 0x0002 /* Server Product ID */
+#define NR_CAPABILITY 0x0004 /* Server Capabilties */
+#define NR_VPD 0x0008 /* Server VPD, if any */
+#define NR_PASSWORD 0x0010 /* Server Password */
+
+/************************************************************************
+ * Registration status of the node's Linux struct tty_driver structures.
+ ************************************************************************/
+#define SERIAL_TTDRV_REG 0x0001 /* nd_serial_ttdriver registered */
+#define CALLOUT_TTDRV_REG 0x0002 /* nd_callout_ttdriver registered */
+#define XPRINT_TTDRV_REG 0x0004 /* nd_xprint_ttdriver registered */
+
+
+/************************************************************************
+ * Node structure. There exists one of these for each associated
+ * realport server.
+ ************************************************************************/
+
+struct nd_struct {
+ struct list_head list;
+ long nd_major; /* Node's major number */
+ long nd_ID; /* Node's ID code */
+
+ char nd_serial_name[50]; /* "tty_dgrp_<id>_" + null */
+ char nd_callout_name[50]; /* "cu_dgrp_<id>_" + null */
+ char nd_xprint_name[50]; /* "pr_dgrp_<id>_" + null */
+
+ char password[16]; /* Password for server, if needed */
+ int nd_tty_ref_cnt; /* Linux tty reference count */
+
+ struct proc_dir_entry *nd_net_de; /* Dir entry for /proc/dgrp/net */
+ struct proc_dir_entry *nd_mon_de; /* Dir entry for /proc/dgrp/mon */
+ struct proc_dir_entry *nd_ports_de; /* Dir entry for /proc/dgrp/ports*/
+ struct proc_dir_entry *nd_dpa_de; /* Dir entry for /proc/dgrp/dpa */
+
+ spinlock_t nd_lock; /* General node lock */
+
+ struct semaphore nd_net_semaphore; /* Net read/write lock */
+ struct semaphore nd_mon_semaphore; /* Monitor buffer lock */
+ spinlock_t nd_dpa_lock; /* DPA buffer lock */
+
+ enum dgrp_nd_state_t nd_state; /* NS_* network state */
+ int nd_chan_count; /* # active channels */
+ int nd_flag; /* Node flags */
+ int nd_send; /* Responses to send */
+ int nd_expect; /* Responses we expect */
+
+ u8 *nd_iobuf; /* Network R/W Buffer */
+ wait_queue_head_t nd_tx_waitq; /* Network select wait queue */
+
+ u8 *nd_inputbuf; /* Input Buffer */
+ u8 *nd_inputflagbuf; /* Input Flags Buffer */
+
+ int nd_tx_deposit; /* Accumulated transmit deposits */
+ int nd_tx_charge; /* Accumulated transmit charges */
+ int nd_tx_credit; /* Current TX credit */
+ int nd_tx_ready; /* Ready to transmit */
+ int nd_tx_work; /* TX work waiting */
+ ulong nd_tx_time; /* Last transmit time */
+ ulong nd_poll_time; /* Next scheduled poll time */
+
+ int nd_delay; /* Current TX delay */
+ int nd_rate; /* Current TX rate */
+ struct link_struct nd_link; /* Link speed params. */
+
+ int nd_seq_in; /* TX seq in ptr */
+ int nd_seq_out; /* TX seq out ptr */
+ int nd_unack; /* Unacknowledged byte count */
+ int nd_remain; /* Remaining receive bytes */
+ int nd_tx_module; /* Current TX module # */
+ int nd_rx_module; /* Current RX module # */
+ char *nd_error; /* Protocol error message */
+
+ int nd_write_count; /* drp_write() call count */
+ int nd_read_count; /* drp_read() count */
+ int nd_send_count; /* TCP message sent */
+ int nd_tx_byte; /* Transmit byte count */
+ int nd_rx_byte; /* Receive byte count */
+
+ ulong nd_mon_lbolt; /* Monitor start time */
+ int nd_mon_flag; /* Monitor flags */
+ int nd_mon_in; /* Monitor in pointer */
+ int nd_mon_out; /* Monitor out pointer */
+ wait_queue_head_t nd_mon_wqueue; /* Monitor wait queue (on flags) */
+ u8 *nd_mon_buf; /* Monitor buffer */
+
+ ulong nd_dpa_lbolt; /* DPA start time */
+ int nd_dpa_flag; /* DPA flags */
+ int nd_dpa_in; /* DPA in pointer */
+ int nd_dpa_out; /* DPA out pointer */
+ wait_queue_head_t nd_dpa_wqueue; /* DPA wait queue (on flags) */
+ u8 *nd_dpa_buf; /* DPA buffer */
+
+ uint nd_dpa_debug;
+ uint nd_dpa_port;
+
+ wait_queue_head_t nd_seq_wque[SEQ_MAX]; /* TX thread wait queues */
+ u8 nd_seq_wait[SEQ_MAX]; /* Transmit thread wait count */
+
+ ushort nd_seq_size[SEQ_MAX]; /* Transmit seq packet size */
+ ulong nd_seq_time[SEQ_MAX]; /* Transmit seq packet time */
+
+ ushort nd_hw_ver; /* HW version returned from PS */
+ ushort nd_sw_ver; /* SW version returned from PS */
+ uint nd_hw_id; /* HW ID returned from PS */
+ u8 nd_ps_desc[MAX_DESC_LEN+1]; /* Description from PS */
+ uint nd_vpd_len; /* VPD len, if any */
+ u8 nd_vpd[VPDSIZE]; /* VPD, if any */
+
+ ulong nd_ttdriver_flags; /* Registration status */
+ struct tty_driver *nd_serial_ttdriver; /* Linux TTYDRIVER structure */
+ struct tty_driver *nd_callout_ttdriver; /* Linux TTYDRIVER structure */
+ struct tty_driver *nd_xprint_ttdriver; /* Linux TTYDRIVER structure */
+
+ u8 *nd_writebuf; /* Used to cache data read
+ * from user
+ */
+ struct ch_struct nd_chan[CHAN_MAX]; /* Channel array */
+ struct device *nd_class_dev; /* Hang our sysfs stuff off of here */
+};
+
+#endif /* __DRP_H */
diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c
index 2cdbf280cdab..d751edfda839 100644
--- a/drivers/staging/ipack/devices/ipoctal.c
+++ b/drivers/staging/ipack/devices/ipoctal.c
@@ -443,7 +443,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
spin_lock_init(&channel->lock);
channel->pointer_read = 0;
channel->pointer_write = 0;
- tty_dev = tty_register_device(tty, i, NULL);
+ tty_dev = tty_port_register_device(&channel->tty_port, tty, i, NULL);
if (IS_ERR(tty_dev)) {
dev_err(&ipoctal->dev->dev, "Failed to register tty device.\n");
continue;
@@ -543,7 +543,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
struct ipoctal_channel *channel = tty->driver_data;
speed_t baud;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
/* Disable and reset everything before change the setup */
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
@@ -564,7 +564,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
default:
mr1 |= MR1_CHRL_8_BITS;
/* By default, select CS8 */
- tty->termios->c_cflag = (cflag & ~CSIZE) | CS8;
+ tty->termios.c_cflag = (cflag & ~CSIZE) | CS8;
break;
}
@@ -578,7 +578,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
mr1 |= MR1_PARITY_OFF;
/* Mark or space parity is not supported */
- tty->termios->c_cflag &= ~CMSPAR;
+ tty->termios.c_cflag &= ~CMSPAR;
/* Set stop bits */
if (cflag & CSTOPB)
@@ -611,10 +611,10 @@ static void ipoctal_set_termios(struct tty_struct *tty,
}
baud = tty_get_baud_rate(tty);
- tty_termios_encode_baud_rate(tty->termios, baud, baud);
+ tty_termios_encode_baud_rate(&tty->termios, baud, baud);
/* Set baud rate */
- switch (tty->termios->c_ospeed) {
+ switch (baud) {
case 75:
csr |= TX_CLK_75 | RX_CLK_75;
break;
@@ -655,7 +655,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
default:
csr |= TX_CLK_38400 | RX_CLK_38400;
/* In case of default, we establish 38400 bps */
- tty_termios_encode_baud_rate(tty->termios, 38400, 38400);
+ tty_termios_encode_baud_rate(&tty->termios, 38400, 38400);
break;
}
diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c
index c56609c6094b..5c969ade2eb7 100644
--- a/drivers/staging/serqt_usb2/serqt_usb2.c
+++ b/drivers/staging/serqt_usb2/serqt_usb2.c
@@ -313,10 +313,8 @@ static void qt_read_bulk_callback(struct urb *urb)
}
tty = tty_port_tty_get(&port->port);
- if (!tty) {
- dbg("%s - bad tty pointer - exiting", __func__);
+ if (!tty)
return;
- }
data = urb->transfer_buffer;
@@ -362,7 +360,7 @@ static void qt_read_bulk_callback(struct urb *urb)
goto exit;
}
- if (tty && RxCount) {
+ if (RxCount) {
flag_data = 0;
for (i = 0; i < RxCount; ++i) {
/* Look ahead code here */
@@ -426,7 +424,7 @@ static void qt_read_bulk_callback(struct urb *urb)
dbg("%s - failed resubmitting read urb, error %d",
__func__, result);
else {
- if (tty && RxCount) {
+ if (RxCount) {
tty_flip_buffer_push(tty);
tty_schedule_flip(tty);
}
@@ -895,8 +893,6 @@ static int qt_open(struct tty_struct *tty,
* Put this here to make it responsive to stty and defaults set by
* the tty layer
*/
- /* FIXME: is this needed? */
- /* qt_set_termios(tty, port, NULL); */
/* Check to see if we've set up our endpoint info yet */
if (port0->open_ports == 1) {
@@ -1193,7 +1189,7 @@ static void qt_set_termios(struct tty_struct *tty,
struct usb_serial_port *port,
struct ktermios *old_termios)
{
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
unsigned char new_LCR = 0;
unsigned int cflag = termios->c_cflag;
unsigned int index;
@@ -1202,7 +1198,7 @@ static void qt_set_termios(struct tty_struct *tty,
index = tty->index - port->serial->minor;
- switch (cflag) {
+ switch (cflag & CSIZE) {
case CS5:
new_LCR |= SERIAL_5_DATA;
break;
@@ -1213,6 +1209,8 @@ static void qt_set_termios(struct tty_struct *tty,
new_LCR |= SERIAL_7_DATA;
break;
default:
+ termios->c_cflag &= ~CSIZE;
+ termios->c_cflag |= CS8;
case CS8:
new_LCR |= SERIAL_8_DATA;
break;
@@ -1299,7 +1297,7 @@ static void qt_set_termios(struct tty_struct *tty,
dbg(__FILE__ "BoxSetSW_FlowCtrl (diabling) failed\n");
}
- tty->termios->c_cflag &= ~CMSPAR;
+ termios->c_cflag &= ~CMSPAR;
/* FIXME: Error cases should be returning the actual bits changed only */
}
diff --git a/drivers/staging/speakup/serialio.h b/drivers/staging/speakup/serialio.h
index 614271f9b99f..55d68b5ad165 100644
--- a/drivers/staging/speakup/serialio.h
+++ b/drivers/staging/speakup/serialio.h
@@ -1,8 +1,7 @@
#ifndef _SPEAKUP_SERIAL_H
#define _SPEAKUP_SERIAL_H
-#include <linux/serial.h> /* for rs_table, serial constants &
- serial_uart_config */
+#include <linux/serial.h> /* for rs_table, serial constants */
#include <linux/serial_reg.h> /* for more serial constants */
#ifndef __sparc__
#include <asm/serial.h>
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index 830cd62d8492..d8e05eeab232 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -214,8 +214,8 @@ config CYCLADES
If you haven't heard about it, it's safe to say N.
config CYZ_INTR
- bool "Cyclades-Z interrupt mode operation (EXPERIMENTAL)"
- depends on EXPERIMENTAL && CYCLADES
+ bool "Cyclades-Z interrupt mode operation"
+ depends on CYCLADES
help
The Cyclades-Z family of multiport cards allows 2 (two) driver op
modes: polling and interrupt. In polling mode, the driver will check
@@ -285,7 +285,7 @@ config SYNCLINK_GT
config NOZOMI
tristate "HSDPA Broadband Wireless Data Card - Globe Trotter"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
If you have a HSDPA driver Broadband Wireless Data Card -
Globe Trotter PCMCIA card, say Y here.
@@ -294,7 +294,7 @@ config NOZOMI
will be called nozomi.
config ISI
- tristate "Multi-Tech multiport card support (EXPERIMENTAL)"
+ tristate "Multi-Tech multiport card support"
depends on SERIAL_NONSTANDARD && PCI
select FW_LOADER
help
@@ -317,7 +317,6 @@ config N_HDLC
config N_GSM
tristate "GSM MUX line discipline support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
depends on NET
help
This line discipline provides support for the GSM MUX protocol and
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 6cc4358f68c1..42d0a2581a87 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -420,7 +420,7 @@ static void check_modem_status(struct serial_state *info)
tty_hangup(port->tty);
}
}
- if (port->flags & ASYNC_CTS_FLOW) {
+ if (tty_port_cts_enabled(port)) {
if (port->tty->hw_stopped) {
if (!(status & SER_CTS)) {
#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
@@ -646,7 +646,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
custom.adkcon = AC_UARTBRK;
mb();
- if (tty->termios->c_cflag & HUPCL)
+ if (tty->termios.c_cflag & HUPCL)
info->MCR &= ~(SER_DTR|SER_RTS);
rtsdtr_ctrl(info->MCR);
@@ -670,7 +670,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
int bits;
unsigned long flags;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
/* Byte size is always 8 bits plus parity bit if requested */
@@ -707,8 +707,8 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
/* If the quotient is zero refuse the change */
if (!quot && old_termios) {
/* FIXME: Will need updating for new tty in the end */
- tty->termios->c_cflag &= ~CBAUD;
- tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+ tty->termios.c_cflag &= ~CBAUD;
+ tty->termios.c_cflag |= (old_termios->c_cflag & CBAUD);
baud = tty_get_baud_rate(tty);
if (!baud)
baud = 9600;
@@ -984,7 +984,7 @@ static void rs_throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
rs_send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
info->MCR &= ~SER_RTS;
local_irq_save(flags);
@@ -1012,7 +1012,7 @@ static void rs_unthrottle(struct tty_struct * tty)
else
rs_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
info->MCR |= SER_RTS;
local_irq_save(flags);
rtsdtr_ctrl(info->MCR);
@@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
- tty_lock();
+ tty_lock(tty);
tmp.line = tty->index;
tmp.port = state->port;
tmp.flags = state->tport.flags;
@@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
tmp.close_delay = state->tport.close_delay;
tmp.closing_wait = state->tport.closing_wait;
tmp.custom_divisor = state->custom_divisor;
- tty_unlock();
+ tty_unlock(tty);
if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
return -EFAULT;
return 0;
@@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
- tty_lock();
+ tty_lock(tty);
change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
new_serial.custom_divisor != state->custom_divisor;
if (new_serial.irq || new_serial.port != state->port ||
new_serial.xmit_fifo_size != state->xmit_fifo_size) {
- tty_unlock();
+ tty_unlock(tty);
return -EINVAL;
}
@@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
(new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
((new_serial.flags & ~ASYNC_USR_MASK) !=
(port->flags & ~ASYNC_USR_MASK))) {
- tty_unlock();
+ tty_unlock(tty);
return -EPERM;
}
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
@@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
}
if (new_serial.baud_base < 9600) {
- tty_unlock();
+ tty_unlock(tty);
return -EINVAL;
}
@@ -1116,7 +1116,7 @@ check_and_exit:
}
} else
retval = startup(tty, state);
- tty_unlock();
+ tty_unlock(tty);
return retval;
}
@@ -1330,7 +1330,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct serial_state *info = tty->driver_data;
unsigned long flags;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = tty->termios.c_cflag;
change_speed(tty, info, old_termios);
@@ -1347,7 +1347,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
if (!(old_termios->c_cflag & CBAUD) &&
(cflag & CBAUD)) {
info->MCR |= SER_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
+ if (!(tty->termios.c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
info->MCR |= SER_RTS;
}
@@ -1358,7 +1358,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
rs_start(tty);
}
@@ -1371,7 +1371,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* or not. Hence, this may change.....
*/
if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios->c_cflag & CLOCAL))
+ (tty->termios.c_cflag & CLOCAL))
wake_up_interruptible(&info->open_wait);
#endif
}
@@ -1710,10 +1710,6 @@ static int __init amiga_serial_probe(struct platform_device *pdev)
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &serial_ops);
- error = tty_register_driver(serial_driver);
- if (error)
- goto fail_put_tty_driver;
-
state = rs_table;
state->port = (int)&custom.serdatr; /* Just to give it a value */
state->custom_divisor = 0;
@@ -1724,6 +1720,11 @@ static int __init amiga_serial_probe(struct platform_device *pdev)
state->icount.overrun = state->icount.brk = 0;
tty_port_init(&state->tport);
state->tport.ops = &amiga_port_ops;
+ tty_port_link_device(&state->tport, serial_driver, 0);
+
+ error = tty_register_driver(serial_driver);
+ if (error)
+ goto fail_put_tty_driver;
printk(KERN_INFO "ttyS0 is the amiga builtin serial port\n");
diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c
index 61fc74fe1747..02b7d3a09696 100644
--- a/drivers/tty/bfin_jtag_comm.c
+++ b/drivers/tty/bfin_jtag_comm.c
@@ -263,6 +263,7 @@ static int __init bfin_jc_init(void)
bfin_jc_driver->subtype = SERIAL_TYPE_NORMAL;
bfin_jc_driver->init_termios = tty_std_termios;
tty_set_operations(bfin_jc_driver, &bfin_jc_ops);
+ tty_port_link_device(&port, bfin_jc_driver, 0);
ret = tty_register_driver(bfin_jc_driver);
if (ret)
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index e61cabdd69df..0a6a0bc1b598 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -727,7 +727,7 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
else
tty_hangup(tty);
}
- if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) {
+ if ((mdm_change & CyCTS) && tty_port_cts_enabled(&info->port)) {
if (tty->hw_stopped) {
if (mdm_status & CyCTS) {
/* cy_start isn't used
@@ -1459,7 +1459,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
info->port.xmit_buf = NULL;
free_page((unsigned long)temp);
}
- if (tty->termios->c_cflag & HUPCL)
+ if (tty->termios.c_cflag & HUPCL)
cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
@@ -1488,7 +1488,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
free_page((unsigned long)temp);
}
- if (tty->termios->c_cflag & HUPCL)
+ if (tty->termios.c_cflag & HUPCL)
tty_port_lower_dtr_rts(&info->port);
set_bit(TTY_IO_ERROR, &tty->flags);
@@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
* If the port is the middle of closing, bail out now
*/
if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
- wait_event_interruptible_tty(info->port.close_wait,
+ wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->port.flags & ASYNC_CLOSING));
return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
}
@@ -1999,14 +1999,11 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
int baud, baud_rate = 0;
int i;
- if (!tty->termios) /* XXX can this happen at all? */
- return;
-
if (info->line == -1)
return;
- cflag = tty->termios->c_cflag;
- iflag = tty->termios->c_iflag;
+ cflag = tty->termios.c_cflag;
+ iflag = tty->termios.c_iflag;
/*
* Set up the tty->alt_speed kludge
@@ -2825,7 +2822,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
cy_set_line_char(info, tty);
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
cy_start(tty);
}
@@ -2837,7 +2834,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* or not. Hence, this may change.....
*/
if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios->c_cflag & CLOCAL))
+ (tty->termios.c_cflag & CLOCAL))
wake_up_interruptible(&info->port.open_wait);
#endif
} /* cy_set_termios */
@@ -2899,7 +2896,7 @@ static void cy_throttle(struct tty_struct *tty)
info->throttle = 1;
}
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
if (!cy_is_Z(card)) {
spin_lock_irqsave(&card->card_lock, flags);
cyy_change_rts_dtr(info, 0, TIOCM_RTS);
@@ -2938,7 +2935,7 @@ static void cy_unthrottle(struct tty_struct *tty)
cy_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
card = info->card;
if (!cy_is_Z(card)) {
spin_lock_irqsave(&card->card_lock, flags);
@@ -3289,9 +3286,10 @@ static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
static int __init cy_detect_isa(void)
{
#ifdef CONFIG_ISA
+ struct cyclades_card *card;
unsigned short cy_isa_irq, nboard;
void __iomem *cy_isa_address;
- unsigned short i, j, cy_isa_nchan;
+ unsigned short i, j, k, cy_isa_nchan;
int isparam = 0;
nboard = 0;
@@ -3349,7 +3347,8 @@ static int __init cy_detect_isa(void)
}
/* fill the next cy_card structure available */
for (j = 0; j < NR_CARDS; j++) {
- if (cy_card[j].base_addr == NULL)
+ card = &cy_card[j];
+ if (card->base_addr == NULL)
break;
}
if (j == NR_CARDS) { /* no more cy_cards available */
@@ -3363,7 +3362,7 @@ static int __init cy_detect_isa(void)
/* allocate IRQ */
if (request_irq(cy_isa_irq, cyy_interrupt,
- 0, "Cyclom-Y", &cy_card[j])) {
+ 0, "Cyclom-Y", card)) {
printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
"could not allocate IRQ#%d.\n",
(unsigned long)cy_isa_address, cy_isa_irq);
@@ -3372,16 +3371,16 @@ static int __init cy_detect_isa(void)
}
/* set cy_card */
- cy_card[j].base_addr = cy_isa_address;
- cy_card[j].ctl_addr.p9050 = NULL;
- cy_card[j].irq = (int)cy_isa_irq;
- cy_card[j].bus_index = 0;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
- cy_card[j].nports = cy_isa_nchan;
- if (cy_init_card(&cy_card[j])) {
- cy_card[j].base_addr = NULL;
- free_irq(cy_isa_irq, &cy_card[j]);
+ card->base_addr = cy_isa_address;
+ card->ctl_addr.p9050 = NULL;
+ card->irq = (int)cy_isa_irq;
+ card->bus_index = 0;
+ card->first_line = cy_next_channel;
+ card->num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
+ card->nports = cy_isa_nchan;
+ if (cy_init_card(card)) {
+ card->base_addr = NULL;
+ free_irq(cy_isa_irq, card);
iounmap(cy_isa_address);
continue;
}
@@ -3393,9 +3392,10 @@ static int __init cy_detect_isa(void)
(unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
cy_isa_irq, cy_isa_nchan, cy_next_channel);
- for (j = cy_next_channel;
- j < cy_next_channel + cy_isa_nchan; j++)
- tty_register_device(cy_serial_driver, j, NULL);
+ for (k = 0, j = cy_next_channel;
+ j < cy_next_channel + cy_isa_nchan; j++, k++)
+ tty_port_register_device(&card->ports[k].port,
+ cy_serial_driver, j, NULL);
cy_next_channel += cy_isa_nchan;
}
return nboard;
@@ -3695,10 +3695,11 @@ err:
static int __devinit cy_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
+ struct cyclades_card *card;
void __iomem *addr0 = NULL, *addr2 = NULL;
char *card_name = NULL;
u32 uninitialized_var(mailbox);
- unsigned int device_id, nchan = 0, card_no, i;
+ unsigned int device_id, nchan = 0, card_no, i, j;
unsigned char plx_ver;
int retval, irq;
@@ -3829,7 +3830,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
}
/* fill the next cy_card structure available */
for (card_no = 0; card_no < NR_CARDS; card_no++) {
- if (cy_card[card_no].base_addr == NULL)
+ card = &cy_card[card_no];
+ if (card->base_addr == NULL)
break;
}
if (card_no == NR_CARDS) { /* no more cy_cards available */
@@ -3843,27 +3845,26 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
/* allocate IRQ */
retval = request_irq(irq, cyy_interrupt,
- IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
+ IRQF_SHARED, "Cyclom-Y", card);
if (retval) {
dev_err(&pdev->dev, "could not allocate IRQ\n");
goto err_unmap;
}
- cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
+ card->num_chips = nchan / CyPORTS_PER_CHIP;
} else {
struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
struct ZFW_CTRL __iomem *zfw_ctrl;
zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- cy_card[card_no].hw_ver = mailbox;
- cy_card[card_no].num_chips = (unsigned int)-1;
- cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
+ card->hw_ver = mailbox;
+ card->num_chips = (unsigned int)-1;
+ card->board_ctrl = &zfw_ctrl->board_ctrl;
#ifdef CONFIG_CYZ_INTR
/* allocate IRQ only if board has an IRQ */
if (irq != 0 && irq != 255) {
retval = request_irq(irq, cyz_interrupt,
- IRQF_SHARED, "Cyclades-Z",
- &cy_card[card_no]);
+ IRQF_SHARED, "Cyclades-Z", card);
if (retval) {
dev_err(&pdev->dev, "could not allocate IRQ\n");
goto err_unmap;
@@ -3873,17 +3874,17 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
}
/* set cy_card */
- cy_card[card_no].base_addr = addr2;
- cy_card[card_no].ctl_addr.p9050 = addr0;
- cy_card[card_no].irq = irq;
- cy_card[card_no].bus_index = 1;
- cy_card[card_no].first_line = cy_next_channel;
- cy_card[card_no].nports = nchan;
- retval = cy_init_card(&cy_card[card_no]);
+ card->base_addr = addr2;
+ card->ctl_addr.p9050 = addr0;
+ card->irq = irq;
+ card->bus_index = 1;
+ card->first_line = cy_next_channel;
+ card->nports = nchan;
+ retval = cy_init_card(card);
if (retval)
goto err_null;
- pci_set_drvdata(pdev, &cy_card[card_no]);
+ pci_set_drvdata(pdev, card);
if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
@@ -3909,14 +3910,15 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
"port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
- for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
- tty_register_device(cy_serial_driver, i, &pdev->dev);
+ for (j = 0, i = cy_next_channel; i < cy_next_channel + nchan; i++, j++)
+ tty_port_register_device(&card->ports[j].port,
+ cy_serial_driver, i, &pdev->dev);
cy_next_channel += nchan;
return 0;
err_null:
- cy_card[card_no].base_addr = NULL;
- free_irq(irq, &cy_card[card_no]);
+ card->base_addr = NULL;
+ free_irq(irq, card);
err_unmap:
iounmap(addr0);
if (addr2)
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 4813684cb634..4ab936b7aac6 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -738,16 +738,17 @@ static int __devinit ehv_bc_tty_probe(struct platform_device *pdev)
goto error;
}
- bc->dev = tty_register_device(ehv_bc_driver, i, &pdev->dev);
+ tty_port_init(&bc->port);
+ bc->port.ops = &ehv_bc_tty_port_ops;
+
+ bc->dev = tty_port_register_device(&bc->port, ehv_bc_driver, i,
+ &pdev->dev);
if (IS_ERR(bc->dev)) {
ret = PTR_ERR(bc->dev);
dev_err(&pdev->dev, "could not register tty (ret=%i)\n", ret);
goto error;
}
- tty_port_init(&bc->port);
- bc->port.ops = &ehv_bc_tty_port_ops;
-
dev_set_drvdata(&pdev->dev, bc);
dev_info(&pdev->dev, "registered /dev/%s%u for byte channel %u\n",
diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig
index 0282a83f51fb..f47b734c6a7a 100644
--- a/drivers/tty/hvc/Kconfig
+++ b/drivers/tty/hvc/Kconfig
@@ -76,7 +76,7 @@ config HVC_XEN_FRONTEND
config HVC_UDBG
bool "udbg based fake hypervisor console"
- depends on PPC && EXPERIMENTAL
+ depends on PPC
select HVC_DRIVER
default n
help
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 2d691eb7c40a..4a652999380f 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -299,20 +299,33 @@ static void hvc_unthrottle(struct tty_struct *tty)
hvc_kick();
}
+static int hvc_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ struct hvc_struct *hp;
+ int rc;
+
+ /* Auto increments kref reference if found. */
+ if (!(hp = hvc_get_by_index(tty->index)))
+ return -ENODEV;
+
+ tty->driver_data = hp;
+
+ rc = tty_port_install(&hp->port, driver, tty);
+ if (rc)
+ tty_port_put(&hp->port);
+ return rc;
+}
+
/*
* The TTY interface won't be used until after the vio layer has exposed the vty
* adapter to the kernel.
*/
static int hvc_open(struct tty_struct *tty, struct file * filp)
{
- struct hvc_struct *hp;
+ struct hvc_struct *hp = tty->driver_data;
unsigned long flags;
int rc = 0;
- /* Auto increments kref reference if found. */
- if (!(hp = hvc_get_by_index(tty->index)))
- return -ENODEV;
-
spin_lock_irqsave(&hp->port.lock, flags);
/* Check and then increment for fast path open. */
if (hp->port.count++ > 0) {
@@ -322,7 +335,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
} /* else count == 0 */
spin_unlock_irqrestore(&hp->port.lock, flags);
- tty->driver_data = hp;
tty_port_tty_set(&hp->port, tty);
if (hp->ops->notifier_add)
@@ -389,6 +401,11 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
hp->vtermno, hp->port.count);
spin_unlock_irqrestore(&hp->port.lock, flags);
}
+}
+
+static void hvc_cleanup(struct tty_struct *tty)
+{
+ struct hvc_struct *hp = tty->driver_data;
tty_port_put(&hp->port);
}
@@ -541,7 +558,7 @@ static int hvc_write_room(struct tty_struct *tty)
struct hvc_struct *hp = tty->driver_data;
if (!hp)
- return -1;
+ return 0;
return hp->outbuf_size - hp->n_outbuf;
}
@@ -792,8 +809,10 @@ static void hvc_poll_put_char(struct tty_driver *driver, int line, char ch)
#endif
static const struct tty_operations hvc_ops = {
+ .install = hvc_install,
.open = hvc_open,
.close = hvc_close,
+ .cleanup = hvc_cleanup,
.write = hvc_write,
.hangup = hvc_hangup,
.unthrottle = hvc_unthrottle,
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index d56788c83974..cab5c7adf8e8 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -1102,27 +1102,20 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
return NULL;
}
-/*
- * This is invoked via the tty_open interface when a user app connects to the
- * /dev node.
- */
-static int hvcs_open(struct tty_struct *tty, struct file *filp)
+static int hvcs_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct hvcs_struct *hvcsd;
- int rc, retval = 0;
- unsigned long flags;
- unsigned int irq;
struct vio_dev *vdev;
- unsigned long unit_address;
-
- if (tty->driver_data)
- goto fast_open;
+ unsigned long unit_address, flags;
+ unsigned int irq;
+ int retval;
/*
* Is there a vty-server that shares the same index?
* This function increments the kref index.
*/
- if (!(hvcsd = hvcs_get_by_index(tty->index))) {
+ hvcsd = hvcs_get_by_index(tty->index);
+ if (!hvcsd) {
printk(KERN_WARNING "HVCS: open failed, no device associated"
" with tty->index %d.\n", tty->index);
return -ENODEV;
@@ -1130,11 +1123,16 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
spin_lock_irqsave(&hvcsd->lock, flags);
- if (hvcsd->connected == 0)
- if ((retval = hvcs_partner_connect(hvcsd)))
- goto error_release;
+ if (hvcsd->connected == 0) {
+ retval = hvcs_partner_connect(hvcsd);
+ if (retval) {
+ spin_unlock_irqrestore(&hvcsd->lock, flags);
+ printk(KERN_WARNING "HVCS: partner connect failed.\n");
+ goto err_put;
+ }
+ }
- hvcsd->port.count = 1;
+ hvcsd->port.count = 0;
hvcsd->port.tty = tty;
tty->driver_data = hvcsd;
@@ -1155,37 +1153,48 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
* This must be done outside of the spinlock because it requests irqs
* and will grab the spinlock and free the connection if it fails.
*/
- if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
- tty_port_put(&hvcsd->port);
+ retval = hvcs_enable_device(hvcsd, unit_address, irq, vdev);
+ if (retval) {
printk(KERN_WARNING "HVCS: enable device failed.\n");
- return rc;
+ goto err_put;
}
- goto open_success;
+ retval = tty_port_install(&hvcsd->port, driver, tty);
+ if (retval)
+ goto err_irq;
-fast_open:
- hvcsd = tty->driver_data;
+ return 0;
+err_irq:
+ spin_lock_irqsave(&hvcsd->lock, flags);
+ vio_disable_interrupts(hvcsd->vdev);
+ spin_unlock_irqrestore(&hvcsd->lock, flags);
+ free_irq(irq, hvcsd);
+err_put:
+ tty_port_put(&hvcsd->port);
+
+ return retval;
+}
+
+/*
+ * This is invoked via the tty_open interface when a user app connects to the
+ * /dev node.
+ */
+static int hvcs_open(struct tty_struct *tty, struct file *filp)
+{
+ struct hvcs_struct *hvcsd = tty->driver_data;
+ unsigned long flags;
spin_lock_irqsave(&hvcsd->lock, flags);
- tty_port_get(&hvcsd->port);
hvcsd->port.count++;
hvcsd->todo_mask |= HVCS_SCHED_READ;
spin_unlock_irqrestore(&hvcsd->lock, flags);
-open_success:
hvcs_kick();
printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n",
hvcsd->vdev->unit_address );
return 0;
-
-error_release:
- spin_unlock_irqrestore(&hvcsd->lock, flags);
- tty_port_put(&hvcsd->port);
-
- printk(KERN_WARNING "HVCS: partner connect failed.\n");
- return retval;
}
static void hvcs_close(struct tty_struct *tty, struct file *filp)
@@ -1236,7 +1245,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
tty->driver_data = NULL;
free_irq(irq, hvcsd);
- tty_port_put(&hvcsd->port);
return;
} else if (hvcsd->port.count < 0) {
printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
@@ -1245,6 +1253,12 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
}
spin_unlock_irqrestore(&hvcsd->lock, flags);
+}
+
+static void hvcs_cleanup(struct tty_struct * tty)
+{
+ struct hvcs_struct *hvcsd = tty->driver_data;
+
tty_port_put(&hvcsd->port);
}
@@ -1431,8 +1445,10 @@ static int hvcs_chars_in_buffer(struct tty_struct *tty)
}
static const struct tty_operations hvcs_ops = {
+ .install = hvcs_install,
.open = hvcs_open,
.close = hvcs_close,
+ .cleanup = hvcs_cleanup,
.hangup = hvcs_hangup,
.write = hvcs_write,
.write_room = hvcs_write_room,
diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c
index 6f5bc49c441f..0083bc1f63f4 100644
--- a/drivers/tty/hvc/hvsi.c
+++ b/drivers/tty/hvc/hvsi.c
@@ -1080,6 +1080,8 @@ static int __init hvsi_init(void)
struct hvsi_struct *hp = &hvsi_ports[i];
int ret = 1;
+ tty_port_link_device(&hp->port, hvsi_driver, i);
+
ret = request_irq(hp->virq, hvsi_interrupt, 0, "hvsi", hp);
if (ret)
printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n",
diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c
index 59c135dd5d20..3396eb9d57a3 100644
--- a/drivers/tty/hvc/hvsi_lib.c
+++ b/drivers/tty/hvc/hvsi_lib.c
@@ -400,7 +400,7 @@ void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp)
spin_unlock_irqrestore(&hp->lock, flags);
/* Clear our own DTR */
- if (!pv->tty || (pv->tty->termios->c_cflag & HUPCL))
+ if (!pv->tty || (pv->tty->termios.c_cflag & HUPCL))
hvsilib_write_mctrl(pv, 0);
/* Tear down the connection */
diff --git a/drivers/tty/ipwireless/network.c b/drivers/tty/ipwireless/network.c
index 57c8b481113f..d2af155dec8b 100644
--- a/drivers/tty/ipwireless/network.c
+++ b/drivers/tty/ipwireless/network.c
@@ -274,7 +274,12 @@ static void do_go_online(struct work_struct *work_go_online)
network->xaccm[0] = ~0U;
network->xaccm[3] = 0x60000000U;
network->raccm = ~0U;
- ppp_register_channel(channel);
+ if (ppp_register_channel(channel) < 0) {
+ printk(KERN_ERR IPWIRELESS_PCCARD_NAME
+ ": unable to register PPP channel\n");
+ kfree(channel);
+ return;
+ }
spin_lock_irqsave(&network->lock, flags);
network->ppp_channel = channel;
}
diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c
index f8b5fa0093a3..160f0ad9589d 100644
--- a/drivers/tty/ipwireless/tty.c
+++ b/drivers/tty/ipwireless/tty.c
@@ -476,7 +476,7 @@ static int add_tty(int j,
mutex_init(&ttys[j]->ipw_tty_mutex);
tty_port_init(&ttys[j]->port);
- tty_register_device(ipw_tty_driver, j, NULL);
+ tty_port_register_device(&ttys[j]->port, ipw_tty_driver, j, NULL);
ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
if (secondary_channel_idx != -1)
diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c
index e1235accab74..d7492e183607 100644
--- a/drivers/tty/isicom.c
+++ b/drivers/tty/isicom.c
@@ -600,7 +600,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
port->status &= ~ISI_DCD;
}
- if (port->port.flags & ASYNC_CTS_FLOW) {
+ if (tty_port_cts_enabled(&port->port)) {
if (tty->hw_stopped) {
if (header & ISI_CTS) {
port->port.tty->hw_stopped = 0;
@@ -702,7 +702,7 @@ static void isicom_config_port(struct tty_struct *tty)
/* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
if (baud < 1 || baud > 4)
- tty->termios->c_cflag &= ~CBAUDEX;
+ tty->termios.c_cflag &= ~CBAUDEX;
else
baud += 15;
}
@@ -1196,8 +1196,8 @@ static void isicom_set_termios(struct tty_struct *tty,
if (isicom_paranoia_check(port, tty->name, "isicom_set_termios"))
return;
- if (tty->termios->c_cflag == old_termios->c_cflag &&
- tty->termios->c_iflag == old_termios->c_iflag)
+ if (tty->termios.c_cflag == old_termios->c_cflag &&
+ tty->termios.c_iflag == old_termios->c_iflag)
return;
spin_lock_irqsave(&port->card->card_lock, flags);
@@ -1205,7 +1205,7 @@ static void isicom_set_termios(struct tty_struct *tty,
spin_unlock_irqrestore(&port->card->card_lock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
isicom_start(tty);
}
@@ -1611,7 +1611,8 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
goto errunri;
for (index = 0; index < board->port_count; index++)
- tty_register_device(isicom_normal, board->index * 16 + index,
+ tty_port_register_device(&board->ports[index].port,
+ isicom_normal, board->index * 16 + index,
&pdev->dev);
return 0;
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index 324467d28a54..56e616b9109a 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -169,6 +169,7 @@ static DEFINE_SPINLOCK(moxa_lock);
static unsigned long baseaddr[MAX_BOARDS];
static unsigned int type[MAX_BOARDS];
static unsigned int numports[MAX_BOARDS];
+static struct tty_port moxa_service_port;
MODULE_AUTHOR("William Chen");
MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
@@ -367,10 +368,10 @@ static int moxa_ioctl(struct tty_struct *tty,
tmp.dcd = 1;
ttyp = tty_port_tty_get(&p->port);
- if (!ttyp || !ttyp->termios)
+ if (!ttyp)
tmp.cflag = p->cflag;
else
- tmp.cflag = ttyp->termios->c_cflag;
+ tmp.cflag = ttyp->termios.c_cflag;
tty_kref_put(ttyp);
copy:
if (copy_to_user(argm, &tmp, sizeof(tmp)))
@@ -834,7 +835,7 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
const struct firmware *fw;
const char *file;
struct moxa_port *p;
- unsigned int i;
+ unsigned int i, first_idx;
int ret;
brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports),
@@ -887,6 +888,11 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
mod_timer(&moxaTimer, jiffies + HZ / 50);
spin_unlock_bh(&moxa_lock);
+ first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
+ for (i = 0; i < brd->numPorts; i++)
+ tty_port_register_device(&brd->ports[i].port, moxaDriver,
+ first_idx + i, dev);
+
return 0;
err_free:
kfree(brd->ports);
@@ -896,7 +902,7 @@ err:
static void moxa_board_deinit(struct moxa_board_conf *brd)
{
- unsigned int a, opened;
+ unsigned int a, opened, first_idx;
mutex_lock(&moxa_openlock);
spin_lock_bh(&moxa_lock);
@@ -925,6 +931,10 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
mutex_lock(&moxa_openlock);
}
+ first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
+ for (a = 0; a < brd->numPorts; a++)
+ tty_unregister_device(moxaDriver, first_idx + a);
+
iounmap(brd->basemem);
brd->basemem = NULL;
kfree(brd->ports);
@@ -967,6 +977,7 @@ static int __devinit moxa_pci_probe(struct pci_dev *pdev,
board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000);
if (board->basemem == NULL) {
dev_err(&pdev->dev, "can't remap io space 2\n");
+ retval = -ENOMEM;
goto err_reg;
}
@@ -1031,9 +1042,14 @@ static int __init moxa_init(void)
printk(KERN_INFO "MOXA Intellio family driver version %s\n",
MOXA_VERSION);
- moxaDriver = alloc_tty_driver(MAX_PORTS + 1);
- if (!moxaDriver)
- return -ENOMEM;
+
+ tty_port_init(&moxa_service_port);
+
+ moxaDriver = tty_alloc_driver(MAX_PORTS + 1,
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV);
+ if (IS_ERR(moxaDriver))
+ return PTR_ERR(moxaDriver);
moxaDriver->name = "ttyMX";
moxaDriver->major = ttymajor;
@@ -1044,8 +1060,9 @@ static int __init moxa_init(void)
moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
moxaDriver->init_termios.c_ispeed = 9600;
moxaDriver->init_termios.c_ospeed = 9600;
- moxaDriver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(moxaDriver, &moxa_ops);
+ /* Having one more port only for ioctls is ugly */
+ tty_port_link_device(&moxa_service_port, moxaDriver, MAX_PORTS);
if (tty_register_driver(moxaDriver)) {
printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
@@ -1178,7 +1195,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
mutex_lock(&ch->port.mutex);
if (!(ch->port.flags & ASYNC_INITIALIZED)) {
ch->statusflags = 0;
- moxa_set_tty_param(tty, tty->termios);
+ moxa_set_tty_param(tty, &tty->termios);
MoxaPortLineCtrl(ch, 1, 1);
MoxaPortEnable(ch);
MoxaSetFifo(ch, ch->type == PORT_16550A);
@@ -1193,7 +1210,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
static void moxa_close(struct tty_struct *tty, struct file *filp)
{
struct moxa_port *ch = tty->driver_data;
- ch->cflag = tty->termios->c_cflag;
+ ch->cflag = tty->termios.c_cflag;
tty_port_close(&ch->port, tty, filp);
}
@@ -1464,7 +1481,7 @@ static void moxa_poll(unsigned long ignored)
static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios)
{
- register struct ktermios *ts = tty->termios;
+ register struct ktermios *ts = &tty->termios;
struct moxa_port *ch = tty->driver_data;
int rts, cts, txflow, rxflow, xany, baud;
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 90cc680c4f0e..cfda47dabd28 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -643,7 +643,7 @@ static int mxser_change_speed(struct tty_struct *tty,
int ret = 0;
unsigned char status;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
if (!info->ioaddr)
return ret;
@@ -830,7 +830,7 @@ static void mxser_check_modem_status(struct tty_struct *tty,
wake_up_interruptible(&port->port.open_wait);
}
- if (port->port.flags & ASYNC_CTS_FLOW) {
+ if (tty_port_cts_enabled(&port->port)) {
if (tty->hw_stopped) {
if (status & UART_MSR_CTS) {
tty->hw_stopped = 0;
@@ -1520,10 +1520,10 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
tty = tty_port_tty_get(port);
- if (!tty || !tty->termios)
+ if (!tty)
ms.cflag = ip->normal_termios.c_cflag;
else
- ms.cflag = tty->termios->c_cflag;
+ ms.cflag = tty->termios.c_cflag;
tty_kref_put(tty);
spin_lock_irq(&ip->slock);
status = inb(ip->ioaddr + UART_MSR);
@@ -1589,13 +1589,13 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
tty = tty_port_tty_get(&ip->port);
- if (!tty || !tty->termios) {
+ if (!tty) {
cflag = ip->normal_termios.c_cflag;
iflag = ip->normal_termios.c_iflag;
me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios);
} else {
- cflag = tty->termios->c_cflag;
- iflag = tty->termios->c_iflag;
+ cflag = tty->termios.c_cflag;
+ iflag = tty->termios.c_iflag;
me->baudrate[p] = tty_get_baud_rate(tty);
}
tty_kref_put(tty);
@@ -1853,7 +1853,7 @@ static void mxser_stoprx(struct tty_struct *tty)
}
}
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
info->MCR &= ~UART_MCR_RTS;
outb(info->MCR, info->ioaddr + UART_MCR);
}
@@ -1890,7 +1890,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
}
}
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
info->MCR |= UART_MCR_RTS;
outb(info->MCR, info->ioaddr + UART_MCR);
}
@@ -1939,14 +1939,14 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
spin_unlock_irqrestore(&info->slock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
mxser_start(tty);
}
/* Handle sw stopped */
if ((old_termios->c_iflag & IXON) &&
- !(tty->termios->c_iflag & IXON)) {
+ !(tty->termios.c_iflag & IXON)) {
tty->stopped = 0;
if (info->board->chip_flag) {
@@ -2337,11 +2337,36 @@ static struct tty_port_operations mxser_port_ops = {
* The MOXA Smartio/Industio serial driver boot-time initialization code!
*/
+static bool allow_overlapping_vector;
+module_param(allow_overlapping_vector, bool, S_IRUGO);
+MODULE_PARM_DESC(allow_overlapping_vector, "whether we allow ISA cards to be configured such that vector overlabs IO ports (default=no)");
+
+static bool mxser_overlapping_vector(struct mxser_board *brd)
+{
+ return allow_overlapping_vector &&
+ brd->vector >= brd->ports[0].ioaddr &&
+ brd->vector < brd->ports[0].ioaddr + 8 * brd->info->nports;
+}
+
+static int mxser_request_vector(struct mxser_board *brd)
+{
+ if (mxser_overlapping_vector(brd))
+ return 0;
+ return request_region(brd->vector, 1, "mxser(vector)") ? 0 : -EIO;
+}
+
+static void mxser_release_vector(struct mxser_board *brd)
+{
+ if (mxser_overlapping_vector(brd))
+ return;
+ release_region(brd->vector, 1);
+}
+
static void mxser_release_ISA_res(struct mxser_board *brd)
{
free_irq(brd->irq, brd);
release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
- release_region(brd->vector, 1);
+ mxser_release_vector(brd);
}
static int __devinit mxser_initbrd(struct mxser_board *brd,
@@ -2396,7 +2421,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,
static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
{
- int id, i, bits;
+ int id, i, bits, ret;
unsigned short regs[16], irq;
unsigned char scratch, scratch2;
@@ -2492,13 +2517,15 @@ static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
8 * brd->info->nports - 1);
return -EIO;
}
- if (!request_region(brd->vector, 1, "mxser(vector)")) {
+
+ ret = mxser_request_vector(brd);
+ if (ret) {
release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
printk(KERN_ERR "mxser: can't request interrupt vector region: "
"0x%.8lx-0x%.8lx\n",
brd->ports[0].ioaddr, brd->ports[0].ioaddr +
8 * brd->info->nports - 1);
- return -EIO;
+ return ret;
}
return brd->info->nports;
@@ -2598,7 +2625,8 @@ static int __devinit mxser_probe(struct pci_dev *pdev,
goto err_rel3;
for (i = 0; i < brd->info->nports; i++)
- tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
+ tty_port_register_device(&brd->ports[i].port, mxvar_sdriver,
+ brd->idx + i, &pdev->dev);
pci_set_drvdata(pdev, brd);
@@ -2695,7 +2723,8 @@ static int __init mxser_module_init(void)
brd->idx = m * MXSER_PORTS_PER_BOARD;
for (i = 0; i < brd->info->nports; i++)
- tty_register_device(mxvar_sdriver, brd->idx + i, NULL);
+ tty_port_register_device(&brd->ports[i].port,
+ mxvar_sdriver, brd->idx + i, NULL);
m++;
}
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index c43b683b6eb8..1e8e8ce55959 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -108,7 +108,7 @@ struct gsm_mux_net {
*/
struct gsm_msg {
- struct gsm_msg *next;
+ struct list_head list;
u8 addr; /* DLCI address + flags */
u8 ctrl; /* Control byte + flags */
unsigned int len; /* Length of data block (can be zero) */
@@ -245,8 +245,7 @@ struct gsm_mux {
unsigned int tx_bytes; /* TX data outstanding */
#define TX_THRESH_HI 8192
#define TX_THRESH_LO 2048
- struct gsm_msg *tx_head; /* Pending data packets */
- struct gsm_msg *tx_tail;
+ struct list_head tx_list; /* Pending data packets */
/* Control messages */
struct timer_list t2_timer; /* Retransmit timer for commands */
@@ -489,7 +488,7 @@ static void gsm_print_packet(const char *hdr, int addr, int cr,
default:
if (!(control & 0x01)) {
pr_cont("I N(S)%d N(R)%d",
- (control & 0x0E) >> 1, (control & 0xE) >> 5);
+ (control & 0x0E) >> 1, (control & 0xE0) >> 5);
} else switch (control & 0x0F) {
case RR:
pr_cont("RR(%d)", (control & 0xE0) >> 5);
@@ -663,7 +662,7 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
m->len = len;
m->addr = addr;
m->ctrl = ctrl;
- m->next = NULL;
+ INIT_LIST_HEAD(&m->list);
return m;
}
@@ -673,22 +672,21 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
*
* The tty device has called us to indicate that room has appeared in
* the transmit queue. Ram more data into the pipe if we have any
+ * If we have been flow-stopped by a CMD_FCOFF, then we can only
+ * send messages on DLCI0 until CMD_FCON
*
* FIXME: lock against link layer control transmissions
*/
static void gsm_data_kick(struct gsm_mux *gsm)
{
- struct gsm_msg *msg = gsm->tx_head;
+ struct gsm_msg *msg, *nmsg;
int len;
int skip_sof = 0;
- /* FIXME: We need to apply this solely to data messages */
- if (gsm->constipated)
- return;
-
- while (gsm->tx_head != NULL) {
- msg = gsm->tx_head;
+ list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) {
+ if (gsm->constipated && msg->addr)
+ continue;
if (gsm->encoding != 0) {
gsm->txframe[0] = GSM1_SOF;
len = gsm_stuff_frame(msg->data,
@@ -711,14 +709,13 @@ static void gsm_data_kick(struct gsm_mux *gsm)
len - skip_sof) < 0)
break;
/* FIXME: Can eliminate one SOF in many more cases */
- gsm->tx_head = msg->next;
- if (gsm->tx_head == NULL)
- gsm->tx_tail = NULL;
gsm->tx_bytes -= msg->len;
- kfree(msg);
/* For a burst of frames skip the extra SOF within the
burst */
skip_sof = 1;
+
+ list_del(&msg->list);
+ kfree(msg);
}
}
@@ -768,11 +765,7 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
msg->data = dp;
/* Add to the actual output queue */
- if (gsm->tx_tail)
- gsm->tx_tail->next = msg;
- else
- gsm->tx_head = msg;
- gsm->tx_tail = msg;
+ list_add_tail(&msg->list, &gsm->tx_list);
gsm->tx_bytes += msg->len;
gsm_data_kick(gsm);
}
@@ -875,7 +868,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
/* dlci->skb is locked by tx_lock */
if (dlci->skb == NULL) {
- dlci->skb = skb_dequeue(&dlci->skb_list);
+ dlci->skb = skb_dequeue_tail(&dlci->skb_list);
if (dlci->skb == NULL)
return 0;
first = 1;
@@ -886,7 +879,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
if (len > gsm->mtu) {
if (dlci->adaption == 3) {
/* Over long frame, bin it */
- kfree_skb(dlci->skb);
+ dev_kfree_skb_any(dlci->skb);
dlci->skb = NULL;
return 0;
}
@@ -899,8 +892,11 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
/* FIXME: need a timer or something to kick this so it can't
get stuck with no work outstanding and no buffer free */
- if (msg == NULL)
+ if (msg == NULL) {
+ skb_queue_tail(&dlci->skb_list, dlci->skb);
+ dlci->skb = NULL;
return -ENOMEM;
+ }
dp = msg->data;
if (dlci->adaption == 4) { /* Interruptible framed (Packetised Data) */
@@ -912,7 +908,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
skb_pull(dlci->skb, len);
__gsm_data_queue(dlci, msg);
if (last) {
- kfree_skb(dlci->skb);
+ dev_kfree_skb_any(dlci->skb);
dlci->skb = NULL;
}
return size;
@@ -971,16 +967,22 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
{
unsigned long flags;
+ int sweep;
+
+ if (dlci->constipated)
+ return;
spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
/* If we have nothing running then we need to fire up */
+ sweep = (dlci->gsm->tx_bytes < TX_THRESH_LO);
if (dlci->gsm->tx_bytes == 0) {
if (dlci->net)
gsm_dlci_data_output_framed(dlci->gsm, dlci);
else
gsm_dlci_data_output(dlci->gsm, dlci);
- } else if (dlci->gsm->tx_bytes < TX_THRESH_LO)
- gsm_dlci_data_sweep(dlci->gsm);
+ }
+ if (sweep)
+ gsm_dlci_data_sweep(dlci->gsm);
spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
}
@@ -1027,6 +1029,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
{
int mlines = 0;
u8 brk = 0;
+ int fc;
/* The modem status command can either contain one octet (v.24 signals)
or two octets (v.24 signals + break signals). The length field will
@@ -1038,19 +1041,21 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
else {
brk = modem & 0x7f;
modem = (modem >> 7) & 0x7f;
- };
+ }
/* Flow control/ready to communicate */
- if (modem & MDM_FC) {
+ fc = (modem & MDM_FC) || !(modem & MDM_RTR);
+ if (fc && !dlci->constipated) {
/* Need to throttle our output on this device */
dlci->constipated = 1;
- }
- if (modem & MDM_RTC) {
- mlines |= TIOCM_DSR | TIOCM_DTR;
+ } else if (!fc && dlci->constipated) {
dlci->constipated = 0;
gsm_dlci_data_kick(dlci);
}
+
/* Map modem bits */
+ if (modem & MDM_RTC)
+ mlines |= TIOCM_DSR | TIOCM_DTR;
if (modem & MDM_RTR)
mlines |= TIOCM_RTS | TIOCM_CTS;
if (modem & MDM_IC)
@@ -1061,7 +1066,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
/* Carrier drop -> hangup */
if (tty) {
if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
- if (!(tty->termios->c_cflag & CLOCAL))
+ if (!(tty->termios.c_cflag & CLOCAL))
tty_hangup(tty);
if (brk & 0x01)
tty_insert_flip_char(tty, 0, TTY_BREAK);
@@ -1190,6 +1195,8 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
u8 *data, int clen)
{
u8 buf[1];
+ unsigned long flags;
+
switch (command) {
case CMD_CLD: {
struct gsm_dlci *dlci = gsm->dlci[0];
@@ -1206,16 +1213,18 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
gsm_control_reply(gsm, CMD_TEST, data, clen);
break;
case CMD_FCON:
- /* Modem wants us to STFU */
- gsm->constipated = 1;
- gsm_control_reply(gsm, CMD_FCON, NULL, 0);
- break;
- case CMD_FCOFF:
/* Modem can accept data again */
gsm->constipated = 0;
- gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
+ gsm_control_reply(gsm, CMD_FCON, NULL, 0);
/* Kick the link in case it is idling */
+ spin_lock_irqsave(&gsm->tx_lock, flags);
gsm_data_kick(gsm);
+ spin_unlock_irqrestore(&gsm->tx_lock, flags);
+ break;
+ case CMD_FCOFF:
+ /* Modem wants us to STFU */
+ gsm->constipated = 1;
+ gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
break;
case CMD_MSC:
/* Out of band modem line change indicator for a DLCI */
@@ -1668,7 +1677,7 @@ static void gsm_dlci_free(struct kref *ref)
dlci->gsm->dlci[dlci->addr] = NULL;
kfifo_free(dlci->fifo);
while ((dlci->skb = skb_dequeue(&dlci->skb_list)))
- kfree_skb(dlci->skb);
+ dev_kfree_skb(dlci->skb);
kfree(dlci);
}
@@ -2007,7 +2016,7 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
{
int i;
struct gsm_dlci *dlci = gsm->dlci[0];
- struct gsm_msg *txq;
+ struct gsm_msg *txq, *ntxq;
struct gsm_control *gc;
gsm->dead = 1;
@@ -2042,11 +2051,9 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
if (gsm->dlci[i])
gsm_dlci_release(gsm->dlci[i]);
/* Now wipe the queues */
- for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) {
- gsm->tx_head = txq->next;
+ list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list)
kfree(txq);
- }
- gsm->tx_tail = NULL;
+ INIT_LIST_HEAD(&gsm->tx_list);
}
EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
@@ -2157,6 +2164,7 @@ struct gsm_mux *gsm_alloc_mux(void)
}
spin_lock_init(&gsm->lock);
kref_init(&gsm->ref);
+ INIT_LIST_HEAD(&gsm->tx_list);
gsm->t1 = T1;
gsm->t2 = T2;
@@ -2273,7 +2281,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
gsm->error(gsm, *dp, flags);
break;
default:
- WARN_ONCE("%s: unknown flag %d\n",
+ WARN_ONCE(1, "%s: unknown flag %d\n",
tty_name(tty, buf), flags);
break;
}
@@ -2377,12 +2385,12 @@ static void gsmld_write_wakeup(struct tty_struct *tty)
/* Queue poll */
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+ spin_lock_irqsave(&gsm->tx_lock, flags);
gsm_data_kick(gsm);
if (gsm->tx_bytes < TX_THRESH_LO) {
- spin_lock_irqsave(&gsm->tx_lock, flags);
gsm_dlci_data_sweep(gsm);
- spin_unlock_irqrestore(&gsm->tx_lock, flags);
}
+ spin_unlock_irqrestore(&gsm->tx_lock, flags);
}
/**
@@ -2868,14 +2876,14 @@ static const struct tty_port_operations gsm_port_ops = {
.dtr_rts = gsm_dtr_rts,
};
-
-static int gsmtty_open(struct tty_struct *tty, struct file *filp)
+static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct gsm_mux *gsm;
struct gsm_dlci *dlci;
- struct tty_port *port;
unsigned int line = tty->index;
unsigned int mux = line >> 6;
+ bool alloc = false;
+ int ret;
line = line & 0x3F;
@@ -2889,14 +2897,35 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
gsm = gsm_mux[mux];
if (gsm->dead)
return -EL2HLT;
+ /* If DLCI 0 is not yet fully open return an error. This is ok from a locking
+ perspective as we don't have to worry about this if DLCI0 is lost */
+ if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN)
+ return -EL2NSYNC;
dlci = gsm->dlci[line];
- if (dlci == NULL)
+ if (dlci == NULL) {
+ alloc = true;
dlci = gsm_dlci_alloc(gsm, line);
+ }
if (dlci == NULL)
return -ENOMEM;
- port = &dlci->port;
- port->count++;
+ ret = tty_port_install(&dlci->port, driver, tty);
+ if (ret) {
+ if (alloc)
+ dlci_put(dlci);
+ return ret;
+ }
+
tty->driver_data = dlci;
+
+ return 0;
+}
+
+static int gsmtty_open(struct tty_struct *tty, struct file *filp)
+{
+ struct gsm_dlci *dlci = tty->driver_data;
+ struct tty_port *port = &dlci->port;
+
+ port->count++;
dlci_get(dlci);
dlci_get(dlci->gsm->dlci[0]);
mux_get(dlci->gsm);
@@ -3043,13 +3072,13 @@ static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
the RPN control message. This however rapidly gets nasty as we
then have to remap modem signals each way according to whether
our virtual cable is null modem etc .. */
- tty_termios_copy_hw(tty->termios, old);
+ tty_termios_copy_hw(&tty->termios, old);
}
static void gsmtty_throttle(struct tty_struct *tty)
{
struct gsm_dlci *dlci = tty->driver_data;
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
dlci->modem_tx &= ~TIOCM_DTR;
dlci->throttled = 1;
/* Send an MSC with DTR cleared */
@@ -3059,7 +3088,7 @@ static void gsmtty_throttle(struct tty_struct *tty)
static void gsmtty_unthrottle(struct tty_struct *tty)
{
struct gsm_dlci *dlci = tty->driver_data;
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
dlci->modem_tx |= TIOCM_DTR;
dlci->throttled = 0;
/* Send an MSC with DTR set */
@@ -3085,6 +3114,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
/* Virtual ttys for the demux */
static const struct tty_operations gsmtty_ops = {
+ .install = gsmtty_install,
.open = gsmtty_open,
.close = gsmtty_close,
.write = gsmtty_write,
diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c
index 5c6c31459a2f..1e6405070ce6 100644
--- a/drivers/tty/n_r3964.c
+++ b/drivers/tty/n_r3964.c
@@ -1065,7 +1065,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
TRACE_L("read()");
- tty_lock();
+ tty_lock(tty);
pClient = findClient(pInfo, task_pid(current));
if (pClient) {
@@ -1077,7 +1077,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
goto unlock;
}
/* block until there is a message: */
- wait_event_interruptible_tty(pInfo->read_wait,
+ wait_event_interruptible_tty(tty, pInfo->read_wait,
(pMsg = remove_msg(pInfo, pClient)));
}
@@ -1107,7 +1107,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
}
ret = -EPERM;
unlock:
- tty_unlock();
+ tty_unlock(tty);
return ret;
}
@@ -1156,7 +1156,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
pHeader->locks = 0;
pHeader->owner = NULL;
- tty_lock();
+ tty_lock(tty);
pClient = findClient(pInfo, task_pid(current));
if (pClient) {
@@ -1175,7 +1175,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
add_tx_queue(pInfo, pHeader);
trigger_transmit(pInfo);
- tty_unlock();
+ tty_unlock(tty);
return 0;
}
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index ee1c268f5f9d..8c0b7b42319c 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -92,10 +92,18 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
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 left;
int old_left;
+ /* tty->read_cnt is not read locked ? */
+ if (I_PARMRK(tty)) {
+ /* Multiply read_cnt by 3, since each byte might take up to
+ * three times as many spaces when PARMRK is set (depending on
+ * its flags, e.g. parity error). */
+ left = N_TTY_BUF_SIZE - tty->read_cnt * 3 - 1;
+ } else
+ left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+
/*
* If we are doing input canonicalization, and there are no
* pending newlines, let characters through without limit, so
@@ -1432,6 +1440,12 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
*/
if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
tty_throttle(tty);
+
+ /* FIXME: there is a tiny race here if the receive room check runs
+ before the other work executes and empties the buffer (upping
+ the receiving room and unthrottling. We then throttle and get
+ stuck. This has been observed and traced down by Vincent Pillet/
+ We need to address this when we sort out out the rx path locking */
}
int is_ignored(int sig)
@@ -1460,7 +1474,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
BUG_ON(!tty);
if (old)
- canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
+ canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON;
if (canon_change) {
memset(&tty->read_flags, 0, sizeof tty->read_flags);
tty->canon_head = tty->read_tail;
@@ -1728,7 +1742,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
do_it_again:
- BUG_ON(!tty->read_buf);
+ if (WARN_ON(!tty->read_buf))
+ return -EAGAIN;
c = job_control(tty, file);
if (c < 0)
@@ -1832,13 +1847,13 @@ do_it_again:
if (tty->icanon && !L_EXTPROC(tty)) {
/* N.B. avoid overrun if nr == 0 */
+ spin_lock_irqsave(&tty->read_lock, flags);
while (nr && tty->read_cnt) {
int eol;
eol = test_and_clear_bit(tty->read_tail,
tty->read_flags);
c = tty->read_buf[tty->read_tail];
- spin_lock_irqsave(&tty->read_lock, flags);
tty->read_tail = ((tty->read_tail+1) &
(N_TTY_BUF_SIZE-1));
tty->read_cnt--;
@@ -1856,15 +1871,19 @@ do_it_again:
if (tty_put_user(tty, c, b++)) {
retval = -EFAULT;
b--;
+ spin_lock_irqsave(&tty->read_lock, flags);
break;
}
nr--;
}
if (eol) {
tty_audit_push(tty);
+ spin_lock_irqsave(&tty->read_lock, flags);
break;
}
+ spin_lock_irqsave(&tty->read_lock, flags);
}
+ spin_unlock_irqrestore(&tty->read_lock, flags);
if (retval)
break;
} else {
diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c
index e7592f9037da..b917c9424954 100644
--- a/drivers/tty/nozomi.c
+++ b/drivers/tty/nozomi.c
@@ -1473,8 +1473,8 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
port->dc = dc;
tty_port_init(&port->port);
port->port.ops = &noz_tty_port_ops;
- tty_dev = tty_register_device(ntty_driver, dc->index_start + i,
- &pdev->dev);
+ tty_dev = tty_port_register_device(&port->port, ntty_driver,
+ dc->index_start + i, &pdev->dev);
if (IS_ERR(tty_dev)) {
ret = PTR_ERR(tty_dev);
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 5505ffc91da4..a82b39939a9c 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -47,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
wake_up_interruptible(&tty->read_wait);
wake_up_interruptible(&tty->write_wait);
tty->packet = 0;
+ /* Review - krefs on tty_link ?? */
if (!tty->link)
return;
tty->link->packet = 0;
@@ -62,9 +63,9 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
mutex_unlock(&devpts_mutex);
}
#endif
- tty_unlock();
+ tty_unlock(tty);
tty_vhangup(tty->link);
- tty_lock();
+ tty_lock(tty);
}
}
@@ -231,8 +232,8 @@ out:
static void pty_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
- tty->termios->c_cflag &= ~(CSIZE | PARENB);
- tty->termios->c_cflag |= (CS8 | CREAD);
+ tty->termios.c_cflag &= ~(CSIZE | PARENB);
+ tty->termios.c_cflag |= (CS8 | CREAD);
}
/**
@@ -282,60 +283,110 @@ done:
return 0;
}
-/* Traditional BSD devices */
-#ifdef CONFIG_LEGACY_PTYS
-
-static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
+/**
+ * pty_common_install - set up the pty pair
+ * @driver: the pty driver
+ * @tty: the tty being instantiated
+ * @bool: legacy, true if this is BSD style
+ *
+ * Perform the initial set up for the tty/pty pair. Called from the
+ * tty layer when the port is first opened.
+ *
+ * Locking: the caller must hold the tty_mutex
+ */
+static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
+ bool legacy)
{
struct tty_struct *o_tty;
+ struct tty_port *ports[2];
int idx = tty->index;
- int retval;
+ int retval = -ENOMEM;
o_tty = alloc_tty_struct();
if (!o_tty)
- return -ENOMEM;
+ goto err;
+ ports[0] = kmalloc(sizeof **ports, GFP_KERNEL);
+ ports[1] = kmalloc(sizeof **ports, GFP_KERNEL);
+ if (!ports[0] || !ports[1])
+ goto err_free_tty;
if (!try_module_get(driver->other->owner)) {
/* This cannot in fact currently happen */
- retval = -ENOMEM;
goto err_free_tty;
}
initialize_tty_struct(o_tty, driver->other, idx);
- /* We always use new tty termios data so we can do this
- the easy way .. */
- retval = tty_init_termios(tty);
- if (retval)
- goto err_deinit_tty;
-
- retval = tty_init_termios(o_tty);
- if (retval)
- goto err_free_termios;
+ if (legacy) {
+ /* We always use new tty termios data so we can do this
+ the easy way .. */
+ retval = tty_init_termios(tty);
+ if (retval)
+ goto err_deinit_tty;
+
+ retval = tty_init_termios(o_tty);
+ if (retval)
+ goto err_free_termios;
+
+ driver->other->ttys[idx] = o_tty;
+ driver->ttys[idx] = tty;
+ } else {
+ memset(&tty->termios_locked, 0, sizeof(tty->termios_locked));
+ tty->termios = driver->init_termios;
+ memset(&o_tty->termios_locked, 0, sizeof(tty->termios_locked));
+ o_tty->termios = driver->other->init_termios;
+ }
/*
* Everything allocated ... set up the o_tty structure.
*/
- driver->other->ttys[idx] = o_tty;
tty_driver_kref_get(driver->other);
if (driver->subtype == PTY_TYPE_MASTER)
o_tty->count++;
/* Establish the links in both directions */
tty->link = o_tty;
o_tty->link = tty;
+ tty_port_init(ports[0]);
+ tty_port_init(ports[1]);
+ o_tty->port = ports[0];
+ tty->port = ports[1];
tty_driver_kref_get(driver);
tty->count++;
- driver->ttys[idx] = tty;
return 0;
err_free_termios:
- tty_free_termios(tty);
+ if (legacy)
+ tty_free_termios(tty);
err_deinit_tty:
deinitialize_tty_struct(o_tty);
module_put(o_tty->driver->owner);
err_free_tty:
+ kfree(ports[0]);
+ kfree(ports[1]);
free_tty_struct(o_tty);
+err:
return retval;
}
+static void pty_cleanup(struct tty_struct *tty)
+{
+ kfree(tty->port);
+}
+
+/* Traditional BSD devices */
+#ifdef CONFIG_LEGACY_PTYS
+
+static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ return pty_common_install(driver, tty, true);
+}
+
+static void pty_remove(struct tty_driver *driver, struct tty_struct *tty)
+{
+ struct tty_struct *pair = tty->link;
+ driver->ttys[tty->index] = NULL;
+ if (pair)
+ pair->driver->ttys[pair->index] = NULL;
+}
+
static int pty_bsd_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
@@ -366,7 +417,9 @@ static const struct tty_operations master_pty_ops_bsd = {
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
.ioctl = pty_bsd_ioctl,
- .resize = pty_resize
+ .cleanup = pty_cleanup,
+ .resize = pty_resize,
+ .remove = pty_remove
};
static const struct tty_operations slave_pty_ops_bsd = {
@@ -379,7 +432,9 @@ static const struct tty_operations slave_pty_ops_bsd = {
.chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
- .resize = pty_resize
+ .cleanup = pty_cleanup,
+ .resize = pty_resize,
+ .remove = pty_remove
};
static void __init legacy_pty_init(void)
@@ -389,12 +444,18 @@ static void __init legacy_pty_init(void)
if (legacy_count <= 0)
return;
- pty_driver = alloc_tty_driver(legacy_count);
- if (!pty_driver)
+ pty_driver = tty_alloc_driver(legacy_count,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_ALLOC);
+ if (IS_ERR(pty_driver))
panic("Couldn't allocate pty driver");
- pty_slave_driver = alloc_tty_driver(legacy_count);
- if (!pty_slave_driver)
+ pty_slave_driver = tty_alloc_driver(legacy_count,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_ALLOC);
+ if (IS_ERR(pty_slave_driver))
panic("Couldn't allocate pty slave driver");
pty_driver->driver_name = "pty_master";
@@ -410,7 +471,6 @@ static void __init legacy_pty_init(void)
pty_driver->init_termios.c_lflag = 0;
pty_driver->init_termios.c_ispeed = 38400;
pty_driver->init_termios.c_ospeed = 38400;
- pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
pty_driver->other = pty_slave_driver;
tty_set_operations(pty_driver, &master_pty_ops_bsd);
@@ -424,8 +484,6 @@ static void __init legacy_pty_init(void)
pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
pty_slave_driver->init_termios.c_ispeed = 38400;
pty_slave_driver->init_termios.c_ospeed = 38400;
- pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS |
- TTY_DRIVER_REAL_RAW;
pty_slave_driver->other = pty_driver;
tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);
@@ -497,78 +555,22 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
return tty;
}
-static void pty_unix98_shutdown(struct tty_struct *tty)
-{
- tty_driver_remove_tty(tty->driver, tty);
- /* We have our own method as we don't use the tty index */
- kfree(tty->termios);
-}
-
/* We have no need to install and remove our tty objects as devpts does all
the work for us */
static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
{
- struct tty_struct *o_tty;
- int idx = tty->index;
-
- o_tty = alloc_tty_struct();
- if (!o_tty)
- return -ENOMEM;
- if (!try_module_get(driver->other->owner)) {
- /* This cannot in fact currently happen */
- 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 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 err_free_mem;
- *o_tty->termios = driver->other->init_termios;
- o_tty->termios_locked = o_tty->termios + 1;
-
- tty_driver_kref_get(driver->other);
- if (driver->subtype == PTY_TYPE_MASTER)
- o_tty->count++;
- /* Establish the links in both directions */
- tty->link = o_tty;
- o_tty->link = tty;
- /*
- * All structures have been allocated, so now we install them.
- * Failures after this point use release_tty to clean up, so
- * there's no need to null out the local pointers.
- */
- tty_driver_kref_get(driver);
- tty->count++;
- return 0;
-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);
- return -ENOMEM;
-}
-
-static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
-{
+ return pty_common_install(driver, tty, false);
}
-static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
+static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
{
}
static const struct tty_operations ptm_unix98_ops = {
.lookup = ptm_unix98_lookup,
.install = pty_unix98_install,
- .remove = ptm_unix98_remove,
+ .remove = pty_unix98_remove,
.open = pty_open,
.close = pty_close,
.write = pty_write,
@@ -578,14 +580,14 @@ static const struct tty_operations ptm_unix98_ops = {
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
.ioctl = pty_unix98_ioctl,
- .shutdown = pty_unix98_shutdown,
- .resize = pty_resize
+ .resize = pty_resize,
+ .cleanup = pty_cleanup
};
static const struct tty_operations pty_unix98_ops = {
.lookup = pts_unix98_lookup,
.install = pty_unix98_install,
- .remove = pts_unix98_remove,
+ .remove = pty_unix98_remove,
.open = pty_open,
.close = pty_close,
.write = pty_write,
@@ -594,7 +596,7 @@ static const struct tty_operations pty_unix98_ops = {
.chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
- .shutdown = pty_unix98_shutdown
+ .cleanup = pty_cleanup,
};
/**
@@ -622,26 +624,28 @@ static int ptmx_open(struct inode *inode, struct file *filp)
return retval;
/* find a device that is not in use. */
- tty_lock();
+ mutex_lock(&devpts_mutex);
index = devpts_new_index(inode);
- tty_unlock();
if (index < 0) {
retval = index;
+ mutex_unlock(&devpts_mutex);
goto err_file;
}
+ mutex_unlock(&devpts_mutex);
+
mutex_lock(&tty_mutex);
- mutex_lock(&devpts_mutex);
tty = tty_init_dev(ptm_driver, index);
- mutex_unlock(&devpts_mutex);
- tty_lock();
- mutex_unlock(&tty_mutex);
if (IS_ERR(tty)) {
retval = PTR_ERR(tty);
goto out;
}
+ /* The tty returned here is locked so we can safely
+ drop the mutex */
+ mutex_unlock(&tty_mutex);
+
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
tty_add_file(tty, filp);
@@ -654,15 +658,15 @@ static int ptmx_open(struct inode *inode, struct file *filp)
if (retval)
goto err_release;
- tty_unlock();
+ tty_unlock(tty);
return 0;
err_release:
- tty_unlock();
+ tty_unlock(tty);
tty_release(inode, filp);
return retval;
out:
+ mutex_unlock(&tty_mutex);
devpts_kill_index(inode, index);
- tty_unlock();
err_file:
tty_free_file(filp);
return retval;
@@ -672,11 +676,21 @@ static struct file_operations ptmx_fops;
static void __init unix98_pty_init(void)
{
- ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
- if (!ptm_driver)
+ ptm_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV |
+ TTY_DRIVER_DEVPTS_MEM |
+ TTY_DRIVER_DYNAMIC_ALLOC);
+ if (IS_ERR(ptm_driver))
panic("Couldn't allocate Unix98 ptm driver");
- pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
- if (!pts_driver)
+ pts_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV |
+ TTY_DRIVER_DEVPTS_MEM |
+ TTY_DRIVER_DYNAMIC_ALLOC);
+ if (IS_ERR(pts_driver))
panic("Couldn't allocate Unix98 pts driver");
ptm_driver->driver_name = "pty_master";
@@ -692,8 +706,6 @@ static void __init unix98_pty_init(void)
ptm_driver->init_termios.c_lflag = 0;
ptm_driver->init_termios.c_ispeed = 38400;
ptm_driver->init_termios.c_ospeed = 38400;
- ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
ptm_driver->other = pts_driver;
tty_set_operations(ptm_driver, &ptm_unix98_ops);
@@ -707,8 +719,6 @@ static void __init unix98_pty_init(void)
pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
pts_driver->init_termios.c_ispeed = 38400;
pts_driver->init_termios.c_ospeed = 38400;
- pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
pts_driver->other = ptm_driver;
tty_set_operations(pts_driver, &pty_unix98_ops);
diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c
index 777d5f9cf6cc..9700d34b20a3 100644
--- a/drivers/tty/rocket.c
+++ b/drivers/tty/rocket.c
@@ -704,8 +704,8 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
spin_lock_init(&info->slock);
mutex_init(&info->write_mtx);
rp_table[line] = info;
- tty_register_device(rocket_driver, line, pci_dev ? &pci_dev->dev :
- NULL);
+ tty_port_register_device(&info->port, rocket_driver, line,
+ pci_dev ? &pci_dev->dev : NULL);
}
/*
@@ -720,7 +720,7 @@ static void configure_r_port(struct tty_struct *tty, struct r_port *info,
unsigned rocketMode;
int bits, baud, divisor;
CHANNEL_t *cp;
- struct ktermios *t = tty->termios;
+ struct ktermios *t = &tty->termios;
cp = &info->channel;
cflag = t->c_cflag;
@@ -978,7 +978,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
tty->alt_speed = 460800;
configure_r_port(tty, info, NULL);
- if (tty->termios->c_cflag & CBAUD) {
+ if (tty->termios.c_cflag & CBAUD) {
sSetDTR(cp);
sSetRTS(cp);
}
@@ -1089,35 +1089,35 @@ static void rp_set_termios(struct tty_struct *tty,
if (rocket_paranoia_check(info, "rp_set_termios"))
return;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
/*
* This driver doesn't support CS5 or CS6
*/
if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6))
- tty->termios->c_cflag =
+ tty->termios.c_cflag =
((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE));
/* Or CMSPAR */
- tty->termios->c_cflag &= ~CMSPAR;
+ tty->termios.c_cflag &= ~CMSPAR;
configure_r_port(tty, info, old_termios);
cp = &info->channel;
/* Handle transition to B0 status */
- if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) {
+ if ((old_termios->c_cflag & CBAUD) && !(tty->termios.c_cflag & CBAUD)) {
sClrDTR(cp);
sClrRTS(cp);
}
/* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) {
- if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS))
+ if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) {
+ if (!tty->hw_stopped || !(tty->termios.c_cflag & CRTSCTS))
sSetRTS(cp);
sSetDTR(cp);
}
- if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
+ if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
rp_start(tty);
}
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
index 3ed20e435e59..66c38a3f74ce 100644
--- a/drivers/tty/serial/68328serial.c
+++ b/drivers/tty/serial/68328serial.c
@@ -515,7 +515,7 @@ static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
unsigned cflag;
int i;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
if (!(port = info->port))
return;
@@ -617,7 +617,7 @@ static void rs_set_ldisc(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->name, "rs_set_ldisc"))
return;
- info->is_cons = (tty->termios->c_line == N_TTY);
+ info->is_cons = (tty->termios.c_line == N_TTY);
printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off");
}
@@ -985,7 +985,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
change_speed(info, tty);
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
rs_start(tty);
}
@@ -1070,7 +1070,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
if (tty->ldisc.close)
(tty->ldisc.close)(tty);
tty->ldisc = ldiscs[N_TTY];
- tty->termios->c_line = N_TTY;
+ tty->termios.c_line = N_TTY;
if (tty->ldisc.open)
(tty->ldisc.open)(tty);
}
@@ -1189,12 +1189,6 @@ rs68328_init(void)
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &rs_ops);
- if (tty_register_driver(serial_driver)) {
- put_tty_driver(serial_driver);
- printk(KERN_ERR "Couldn't register serial driver\n");
- return -ENOMEM;
- }
-
local_irq_save(flags);
for(i=0;i<NR_PORTS;i++) {
@@ -1224,8 +1218,17 @@ rs68328_init(void)
0,
"M68328_UART", info))
panic("Unable to attach 68328 serial interrupt\n");
+
+ tty_port_link_device(&info->tport, serial_driver, i);
}
local_irq_restore(flags);
+
+ if (tty_register_driver(serial_driver)) {
+ put_tty_driver(serial_driver);
+ printk(KERN_ERR "Couldn't register serial driver\n");
+ return -ENOMEM;
+ }
+
return 0;
}
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
index 8123f784bcda..3ba4234592bc 100644
--- a/drivers/tty/serial/8250/8250.c
+++ b/drivers/tty/serial/8250/8250.c
@@ -290,6 +290,9 @@ static const struct serial8250_config uart_config[] = {
UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00,
.flags = UART_CAP_FIFO,
},
+ [PORT_8250_CIR] = {
+ .name = "CIR port"
+ }
};
/* Uart divisor latch read */
@@ -1037,6 +1040,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
unsigned char save_lcr, save_mcr;
struct uart_port *port = &up->port;
unsigned long flags;
+ unsigned int old_capabilities;
if (!port->iobase && !port->mapbase && !port->membase)
return;
@@ -1087,6 +1091,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
/*
* We failed; there's nothing here
*/
+ spin_unlock_irqrestore(&port->lock, flags);
DEBUG_AUTOCONF("IER test failed (%02x, %02x) ",
scratch2, scratch3);
goto out;
@@ -1110,6 +1115,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
status1 = serial_in(up, UART_MSR) & 0xF0;
serial_out(up, UART_MCR, save_mcr);
if (status1 != 0x90) {
+ spin_unlock_irqrestore(&port->lock, flags);
DEBUG_AUTOCONF("LOOP test failed (%02x) ",
status1);
goto out;
@@ -1132,8 +1138,6 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
scratch = serial_in(up, UART_IIR) >> 6;
- DEBUG_AUTOCONF("iir=%d ", scratch);
-
switch (scratch) {
case 0:
autoconfig_8250(up);
@@ -1167,19 +1171,13 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
serial_out(up, UART_LCR, save_lcr);
- if (up->capabilities != uart_config[port->type].flags) {
- printk(KERN_WARNING
- "ttyS%d: detected caps %08x should be %08x\n",
- serial_index(port), up->capabilities,
- uart_config[port->type].flags);
- }
-
port->fifosize = uart_config[up->port.type].fifo_size;
+ old_capabilities = up->capabilities;
up->capabilities = uart_config[port->type].flags;
up->tx_loadsz = uart_config[port->type].tx_loadsz;
if (port->type == PORT_UNKNOWN)
- goto out;
+ goto out_lock;
/*
* Reset the UART.
@@ -1196,8 +1194,16 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
else
serial_out(up, UART_IER, 0);
- out:
+out_lock:
spin_unlock_irqrestore(&port->lock, flags);
+ if (up->capabilities != old_capabilities) {
+ printk(KERN_WARNING
+ "ttyS%d: detected caps %08x should be %08x\n",
+ serial_index(port), old_capabilities,
+ up->capabilities);
+ }
+out:
+ DEBUG_AUTOCONF("iir=%d ", scratch);
DEBUG_AUTOCONF("type=%s\n", uart_config[port->type].name);
}
@@ -1897,6 +1903,9 @@ static int serial8250_startup(struct uart_port *port)
unsigned char lsr, iir;
int retval;
+ if (port->type == PORT_8250_CIR)
+ return -ENODEV;
+
port->fifosize = uart_config[up->port.type].fifo_size;
up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
up->capabilities = uart_config[up->port.type].flags;
@@ -2202,6 +2211,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned char cval, fcr = 0;
unsigned long flags;
unsigned int baud, quot;
+ int fifo_bug = 0;
switch (termios->c_cflag & CSIZE) {
case CS5:
@@ -2221,8 +2231,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
if (termios->c_cflag & CSTOPB)
cval |= UART_LCR_STOP;
- if (termios->c_cflag & PARENB)
+ if (termios->c_cflag & PARENB) {
cval |= UART_LCR_PARITY;
+ if (up->bugs & UART_BUG_PARITY)
+ fifo_bug = 1;
+ }
if (!(termios->c_cflag & PARODD))
cval |= UART_LCR_EPAR;
#ifdef CMSPAR
@@ -2246,7 +2259,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
fcr = uart_config[port->type].fcr;
- if (baud < 2400) {
+ if (baud < 2400 || fifo_bug) {
fcr &= ~UART_FCR_TRIGGER_MASK;
fcr |= UART_FCR_TRIGGER_1;
}
@@ -2336,7 +2349,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
serial_port_out(port, UART_EFR, efr);
}
-#ifdef CONFIG_ARCH_OMAP
+#ifdef CONFIG_ARCH_OMAP1
/* Workaround to enable 115200 baud on OMAP1510 internal ports */
if (cpu_is_omap1510() && is_omap_port(up)) {
if (baud == 115200) {
@@ -2426,7 +2439,7 @@ static unsigned int serial8250_port_size(struct uart_8250_port *pt)
{
if (pt->port.iotype == UPIO_AU)
return 0x1000;
-#ifdef CONFIG_ARCH_OMAP
+#ifdef CONFIG_ARCH_OMAP1
if (is_omap_port(pt))
return 0x16 << pt->port.regshift;
#endif
@@ -2550,7 +2563,10 @@ static int serial8250_request_port(struct uart_port *port)
{
struct uart_8250_port *up =
container_of(port, struct uart_8250_port, port);
- int ret = 0;
+ int ret;
+
+ if (port->type == PORT_8250_CIR)
+ return -ENODEV;
ret = serial8250_request_std_resource(up);
if (ret == 0 && port->type == PORT_RSA) {
@@ -2569,6 +2585,9 @@ static void serial8250_config_port(struct uart_port *port, int flags)
int probeflags = PROBE_ANY;
int ret;
+ if (port->type == PORT_8250_CIR)
+ return;
+
/*
* Find the region that we can probe for. This in turn
* tells us whether we can probe for the type of port.
@@ -2668,6 +2687,9 @@ static void __init serial8250_isa_init_ports(void)
return;
first = 0;
+ if (nr_uarts > UART_NR)
+ nr_uarts = UART_NR;
+
for (i = 0; i < nr_uarts; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
struct uart_port *port = &up->port;
@@ -2677,6 +2699,7 @@ static void __init serial8250_isa_init_ports(void)
init_timer(&up->timer);
up->timer.function = serial8250_timeout;
+ up->cur_iotype = 0xFF;
/*
* ALPHA_KLUDGE_MCR needs to be killed.
@@ -2728,13 +2751,9 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
for (i = 0; i < nr_uarts; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
- up->cur_iotype = 0xFF;
- }
-
- serial8250_isa_init_ports();
- for (i = 0; i < nr_uarts; i++) {
- struct uart_8250_port *up = &serial8250_ports[i];
+ if (up->port.dev)
+ continue;
up->port.dev = dev;
@@ -2859,9 +2878,6 @@ static struct console serial8250_console = {
static int __init serial8250_console_init(void)
{
- if (nr_uarts > UART_NR)
- nr_uarts = UART_NR;
-
serial8250_isa_init_ports();
register_console(&serial8250_console);
return 0;
@@ -2979,36 +2995,36 @@ void serial8250_resume_port(int line)
static int __devinit serial8250_probe(struct platform_device *dev)
{
struct plat_serial8250_port *p = dev->dev.platform_data;
- struct uart_port port;
+ struct uart_8250_port uart;
int ret, i, irqflag = 0;
- memset(&port, 0, sizeof(struct uart_port));
+ memset(&uart, 0, sizeof(uart));
if (share_irqs)
irqflag = IRQF_SHARED;
for (i = 0; p && p->flags != 0; p++, i++) {
- port.iobase = p->iobase;
- port.membase = p->membase;
- port.irq = p->irq;
- port.irqflags = p->irqflags;
- port.uartclk = p->uartclk;
- port.regshift = p->regshift;
- port.iotype = p->iotype;
- port.flags = p->flags;
- port.mapbase = p->mapbase;
- port.hub6 = p->hub6;
- port.private_data = p->private_data;
- port.type = p->type;
- port.serial_in = p->serial_in;
- port.serial_out = p->serial_out;
- port.handle_irq = p->handle_irq;
- port.handle_break = p->handle_break;
- port.set_termios = p->set_termios;
- port.pm = p->pm;
- port.dev = &dev->dev;
- port.irqflags |= irqflag;
- ret = serial8250_register_port(&port);
+ uart.port.iobase = p->iobase;
+ uart.port.membase = p->membase;
+ uart.port.irq = p->irq;
+ uart.port.irqflags = p->irqflags;
+ uart.port.uartclk = p->uartclk;
+ uart.port.regshift = p->regshift;
+ uart.port.iotype = p->iotype;
+ uart.port.flags = p->flags;
+ uart.port.mapbase = p->mapbase;
+ uart.port.hub6 = p->hub6;
+ uart.port.private_data = p->private_data;
+ uart.port.type = p->type;
+ uart.port.serial_in = p->serial_in;
+ uart.port.serial_out = p->serial_out;
+ uart.port.handle_irq = p->handle_irq;
+ uart.port.handle_break = p->handle_break;
+ uart.port.set_termios = p->set_termios;
+ uart.port.pm = p->pm;
+ uart.port.dev = &dev->dev;
+ uart.port.irqflags |= irqflag;
+ ret = serial8250_register_8250_port(&uart);
if (ret < 0) {
dev_err(&dev->dev, "unable to register port at index %d "
"(IO%lx MEM%llx IRQ%d): %d\n", i,
@@ -3081,7 +3097,7 @@ static struct platform_driver serial8250_isa_driver = {
static struct platform_device *serial8250_isa_devs;
/*
- * serial8250_register_port and serial8250_unregister_port allows for
+ * serial8250_register_8250_port and serial8250_unregister_port allows for
* 16x50 serial ports to be configured at run-time, to support PCMCIA
* modems and PCI multiport cards.
*/
@@ -3143,8 +3159,9 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
mutex_lock(&serial_mutex);
uart = serial8250_find_match_or_unused(&up->port);
- if (uart) {
- uart_remove_one_port(&serial8250_reg, &uart->port);
+ if (uart && uart->port.type != PORT_8250_CIR) {
+ if (uart->port.dev)
+ uart_remove_one_port(&serial8250_reg, &uart->port);
uart->port.iobase = up->port.iobase;
uart->port.membase = up->port.membase;
@@ -3155,6 +3172,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->port.regshift = up->port.regshift;
uart->port.iotype = up->port.iotype;
uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
+ uart->bugs = up->bugs;
uart->port.mapbase = up->port.mapbase;
uart->port.private_data = up->port.private_data;
if (up->port.dev)
@@ -3198,29 +3216,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
EXPORT_SYMBOL(serial8250_register_8250_port);
/**
- * serial8250_register_port - register a serial port
- * @port: serial port template
- *
- * Configure the serial port specified by the request. If the
- * port exists and is in use, it is hung up and unregistered
- * first.
- *
- * The port is then probed and if necessary the IRQ is autodetected
- * If this fails an error is returned.
- *
- * On success the port is ready to use and the line number is returned.
- */
-int serial8250_register_port(struct uart_port *port)
-{
- struct uart_8250_port up;
-
- memset(&up, 0, sizeof(up));
- memcpy(&up.port, port, sizeof(*port));
- return serial8250_register_8250_port(&up);
-}
-EXPORT_SYMBOL(serial8250_register_port);
-
-/**
* serial8250_unregister_port - remove a 16x50 serial port at runtime
* @line: serial line number
*
@@ -3250,8 +3245,7 @@ static int __init serial8250_init(void)
{
int ret;
- if (nr_uarts > UART_NR)
- nr_uarts = UART_NR;
+ serial8250_isa_init_ports();
printk(KERN_INFO "Serial: 8250/16550 driver, "
"%d ports, IRQ sharing %sabled\n", nr_uarts,
@@ -3266,11 +3260,15 @@ static int __init serial8250_init(void)
if (ret)
goto out;
+ ret = serial8250_pnp_init();
+ if (ret)
+ goto unreg_uart_drv;
+
serial8250_isa_devs = platform_device_alloc("serial8250",
PLAT8250_DEV_LEGACY);
if (!serial8250_isa_devs) {
ret = -ENOMEM;
- goto unreg_uart_drv;
+ goto unreg_pnp;
}
ret = platform_device_add(serial8250_isa_devs);
@@ -3286,6 +3284,8 @@ static int __init serial8250_init(void)
platform_device_del(serial8250_isa_devs);
put_dev:
platform_device_put(serial8250_isa_devs);
+unreg_pnp:
+ serial8250_pnp_exit();
unreg_uart_drv:
#ifdef CONFIG_SPARC
sunserial_unregister_minors(&serial8250_reg, UART_NR);
@@ -3310,6 +3310,8 @@ static void __exit serial8250_exit(void)
platform_driver_unregister(&serial8250_isa_driver);
platform_device_unregister(isa_dev);
+ serial8250_pnp_exit();
+
#ifdef CONFIG_SPARC
sunserial_unregister_minors(&serial8250_reg, UART_NR);
#else
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index f9719d167c8d..5a76f9c8d36b 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -13,36 +13,6 @@
#include <linux/serial_8250.h>
-struct uart_8250_port {
- struct uart_port port;
- struct timer_list timer; /* "no irq" timer */
- struct list_head list; /* ports on this IRQ */
- unsigned short capabilities; /* port capabilities */
- unsigned short bugs; /* port bugs */
- unsigned int tx_loadsz; /* transmit fifo load size */
- unsigned char acr;
- unsigned char ier;
- unsigned char lcr;
- unsigned char mcr;
- unsigned char mcr_mask; /* mask of user bits */
- unsigned char mcr_force; /* mask of forced bits */
- unsigned char cur_iotype; /* Running I/O type */
-
- /*
- * Some bits in registers are cleared on a read, so they must
- * be saved whenever the register is read but the bits will not
- * be immediately processed.
- */
-#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
- unsigned char lsr_saved_flags;
-#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
- unsigned char msr_saved_flags;
-
- /* 8250 specific callbacks */
- int (*dl_read)(struct uart_8250_port *);
- void (*dl_write)(struct uart_8250_port *, int);
-};
-
struct old_serial_port {
unsigned int uart;
unsigned int baud_base;
@@ -56,9 +26,6 @@ struct old_serial_port {
unsigned long irqflags;
};
-/*
- * This replaces serial_uart_config in include/linux/serial.h
- */
struct serial8250_config {
const char *name;
unsigned short fifo_size;
@@ -78,6 +45,7 @@ struct serial8250_config {
#define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */
#define UART_BUG_NOMSR (1 << 2) /* UART has buggy MSR status bits (Au1x00) */
#define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */
+#define UART_BUG_PARITY (1 << 4) /* UART mishandles parity if FIFO enabled */
#define PROBE_RSA (1 << 0)
#define PROBE_ANY (~0)
@@ -129,3 +97,12 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
#else
#define ALPHA_KLUDGE_MCR 0
#endif
+
+#ifdef CONFIG_SERIAL_8250_PNP
+int serial8250_pnp_init(void);
+void serial8250_pnp_exit(void);
+#else
+static inline int serial8250_pnp_init(void) { return 0; }
+static inline void serial8250_pnp_exit(void) { }
+#endif
+
diff --git a/drivers/tty/serial/8250/8250_acorn.c b/drivers/tty/serial/8250/8250_acorn.c
index b0ce8c56f1a4..857498312a9a 100644
--- a/drivers/tty/serial/8250/8250_acorn.c
+++ b/drivers/tty/serial/8250/8250_acorn.c
@@ -43,7 +43,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
{
struct serial_card_info *info;
struct serial_card_type *type = id->data;
- struct uart_port port;
+ struct uart_8250_port uart;
unsigned long bus_addr;
unsigned int i;
@@ -62,19 +62,19 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
ecard_set_drvdata(ec, info);
- memset(&port, 0, sizeof(struct uart_port));
- port.irq = ec->irq;
- port.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
- port.uartclk = type->uartclk;
- port.iotype = UPIO_MEM;
- port.regshift = 2;
- port.dev = &ec->dev;
+ memset(&uart, 0, sizeof(struct uart_8250_port));
+ uart.port.irq = ec->irq;
+ uart.port.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+ uart.port.uartclk = type->uartclk;
+ uart.port.iotype = UPIO_MEM;
+ uart.port.regshift = 2;
+ uart.port.dev = &ec->dev;
for (i = 0; i < info->num_ports; i ++) {
- port.membase = info->vaddr + type->offset[i];
- port.mapbase = bus_addr + type->offset[i];
+ uart.port.membase = info->vaddr + type->offset[i];
+ uart.port.mapbase = bus_addr + type->offset[i];
- info->ports[i] = serial8250_register_port(&port);
+ info->ports[i] = serial8250_register_8250_port(&uart);
}
return 0;
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index f574eef3075f..c3b2ec0c8c0b 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -89,7 +89,7 @@ static int dw8250_handle_irq(struct uart_port *p)
static int __devinit dw8250_probe(struct platform_device *pdev)
{
- struct uart_port port = {};
+ struct uart_8250_port uart = {};
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
struct device_node *np = pdev->dev.of_node;
@@ -104,28 +104,28 @@ static int __devinit dw8250_probe(struct platform_device *pdev)
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- port.private_data = data;
-
- spin_lock_init(&port.lock);
- port.mapbase = regs->start;
- port.irq = irq->start;
- port.handle_irq = dw8250_handle_irq;
- port.type = PORT_8250;
- port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP |
+ uart.port.private_data = data;
+
+ spin_lock_init(&uart.port.lock);
+ uart.port.mapbase = regs->start;
+ uart.port.irq = irq->start;
+ uart.port.handle_irq = dw8250_handle_irq;
+ uart.port.type = PORT_8250;
+ uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP |
UPF_FIXED_PORT | UPF_FIXED_TYPE;
- port.dev = &pdev->dev;
+ uart.port.dev = &pdev->dev;
- port.iotype = UPIO_MEM;
- port.serial_in = dw8250_serial_in;
- port.serial_out = dw8250_serial_out;
+ uart.port.iotype = UPIO_MEM;
+ uart.port.serial_in = dw8250_serial_in;
+ uart.port.serial_out = dw8250_serial_out;
if (!of_property_read_u32(np, "reg-io-width", &val)) {
switch (val) {
case 1:
break;
case 4:
- port.iotype = UPIO_MEM32;
- port.serial_in = dw8250_serial_in32;
- port.serial_out = dw8250_serial_out32;
+ uart.port.iotype = UPIO_MEM32;
+ uart.port.serial_in = dw8250_serial_in32;
+ uart.port.serial_out = dw8250_serial_out32;
break;
default:
dev_err(&pdev->dev, "unsupported reg-io-width (%u)\n",
@@ -135,15 +135,15 @@ static int __devinit dw8250_probe(struct platform_device *pdev)
}
if (!of_property_read_u32(np, "reg-shift", &val))
- port.regshift = val;
+ uart.port.regshift = val;
if (of_property_read_u32(np, "clock-frequency", &val)) {
dev_err(&pdev->dev, "no clock-frequency property set\n");
return -EINVAL;
}
- port.uartclk = val;
+ uart.port.uartclk = val;
- data->line = serial8250_register_port(&port);
+ data->line = serial8250_register_8250_port(&uart);
if (data->line < 0)
return data->line;
diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c
index d8c0ffbfa6e3..097dff9c08ad 100644
--- a/drivers/tty/serial/8250/8250_gsc.c
+++ b/drivers/tty/serial/8250/8250_gsc.c
@@ -26,7 +26,7 @@
static int __init serial_init_chip(struct parisc_device *dev)
{
- struct uart_port port;
+ struct uart_8250_port uart;
unsigned long address;
int err;
@@ -48,21 +48,21 @@ static int __init serial_init_chip(struct parisc_device *dev)
if (dev->id.sversion != 0x8d)
address += 0x800;
- memset(&port, 0, sizeof(port));
- port.iotype = UPIO_MEM;
+ memset(&uart, 0, sizeof(uart));
+ uart.port.iotype = UPIO_MEM;
/* 7.272727MHz on Lasi. Assumed the same for Dino, Wax and Timi. */
- port.uartclk = 7272727;
- port.mapbase = address;
- port.membase = ioremap_nocache(address, 16);
- port.irq = dev->irq;
- port.flags = UPF_BOOT_AUTOCONF;
- port.dev = &dev->dev;
-
- err = serial8250_register_port(&port);
+ uart.port.uartclk = 7272727;
+ uart.port.mapbase = address;
+ uart.port.membase = ioremap_nocache(address, 16);
+ uart.port.irq = dev->irq;
+ uart.port.flags = UPF_BOOT_AUTOCONF;
+ uart.port.dev = &dev->dev;
+
+ err = serial8250_register_8250_port(&uart);
if (err < 0) {
printk(KERN_WARNING
- "serial8250_register_port returned error %d\n", err);
- iounmap(port.membase);
+ "serial8250_register_8250_port returned error %d\n", err);
+ iounmap(uart.port.membase);
return err;
}
diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c
index c13438c93012..8f1dd2cc00a8 100644
--- a/drivers/tty/serial/8250/8250_hp300.c
+++ b/drivers/tty/serial/8250/8250_hp300.c
@@ -171,7 +171,7 @@ static int __devinit hpdca_init_one(struct dio_dev *d,
return 0;
}
#endif
- memset(&port, 0, sizeof(struct uart_port));
+ memset(&uart, 0, sizeof(uart));
/* Memory mapped I/O */
port.iotype = UPIO_MEM;
@@ -182,7 +182,7 @@ static int __devinit hpdca_init_one(struct dio_dev *d,
port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
port.regshift = 1;
port.dev = &d->dev;
- line = serial8250_register_port(&port);
+ line = serial8250_register_8250_port(&uart);
if (line < 0) {
printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
@@ -210,7 +210,7 @@ static int __init hp300_8250_init(void)
#ifdef CONFIG_HPAPCI
int line;
unsigned long base;
- struct uart_port uport;
+ struct uart_8250_port uart;
struct hp300_port *port;
int i;
#endif
@@ -248,26 +248,26 @@ static int __init hp300_8250_init(void)
if (!port)
return -ENOMEM;
- memset(&uport, 0, sizeof(struct uart_port));
+ memset(&uart, 0, sizeof(uart));
base = (FRODO_BASE + FRODO_APCI_OFFSET(i));
/* Memory mapped I/O */
- uport.iotype = UPIO_MEM;
- uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
+ uart.port.iotype = UPIO_MEM;
+ uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
| UPF_BOOT_AUTOCONF;
/* XXX - no interrupt support yet */
- uport.irq = 0;
- uport.uartclk = HPAPCI_BAUD_BASE * 16;
- uport.mapbase = base;
- uport.membase = (char *)(base + DIO_VIRADDRBASE);
- uport.regshift = 2;
+ uart.port.irq = 0;
+ uart.port.uartclk = HPAPCI_BAUD_BASE * 16;
+ uart.port.mapbase = base;
+ uart.port.membase = (char *)(base + DIO_VIRADDRBASE);
+ uart.port.regshift = 2;
- line = serial8250_register_port(&uport);
+ line = serial8250_register_8250_port(&uart);
if (line < 0) {
printk(KERN_NOTICE "8250_hp300: register_serial() APCI"
- " %d irq %d failed\n", i, uport.irq);
+ " %d irq %d failed\n", i, uart.port.irq);
kfree(port);
continue;
}
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 452278efef29..17b7d26abf41 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -44,7 +44,7 @@ struct pci_serial_quirk {
int (*init)(struct pci_dev *dev);
int (*setup)(struct serial_private *,
const struct pciserial_board *,
- struct uart_port *, int);
+ struct uart_8250_port *, int);
void (*exit)(struct pci_dev *dev);
};
@@ -59,7 +59,7 @@ struct serial_private {
};
static int pci_default_setup(struct serial_private*,
- const struct pciserial_board*, struct uart_port*, int);
+ const struct pciserial_board*, struct uart_8250_port *, int);
static void moan_device(const char *str, struct pci_dev *dev)
{
@@ -74,7 +74,7 @@ static void moan_device(const char *str, struct pci_dev *dev)
}
static int
-setup_port(struct serial_private *priv, struct uart_port *port,
+setup_port(struct serial_private *priv, struct uart_8250_port *port,
int bar, int offset, int regshift)
{
struct pci_dev *dev = priv->dev;
@@ -93,17 +93,17 @@ setup_port(struct serial_private *priv, struct uart_port *port,
if (!priv->remapped_bar[bar])
return -ENOMEM;
- port->iotype = UPIO_MEM;
- port->iobase = 0;
- port->mapbase = base + offset;
- port->membase = priv->remapped_bar[bar] + offset;
- port->regshift = regshift;
+ port->port.iotype = UPIO_MEM;
+ port->port.iobase = 0;
+ port->port.mapbase = base + offset;
+ port->port.membase = priv->remapped_bar[bar] + offset;
+ port->port.regshift = regshift;
} else {
- port->iotype = UPIO_PORT;
- port->iobase = base + offset;
- port->mapbase = 0;
- port->membase = NULL;
- port->regshift = 0;
+ port->port.iotype = UPIO_PORT;
+ port->port.iobase = base + offset;
+ port->port.mapbase = 0;
+ port->port.membase = NULL;
+ port->port.regshift = 0;
}
return 0;
}
@@ -113,7 +113,7 @@ setup_port(struct serial_private *priv, struct uart_port *port,
*/
static int addidata_apci7800_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int bar = 0, offset = board->first_offset;
bar = FL_GET_BASE(board->flags);
@@ -140,7 +140,7 @@ static int addidata_apci7800_setup(struct serial_private *priv,
*/
static int
afavlab_setup(struct serial_private *priv, const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int bar, offset = board->first_offset;
@@ -195,7 +195,7 @@ static int pci_hp_diva_init(struct pci_dev *dev)
static int
pci_hp_diva_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int offset = board->first_offset;
unsigned int bar = FL_GET_BASE(board->flags);
@@ -370,7 +370,7 @@ static void __devexit pci_ni8430_exit(struct pci_dev *dev)
/* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */
static int
sbs_setup(struct serial_private *priv, const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int bar, offset = board->first_offset;
@@ -525,7 +525,7 @@ static int pci_siig_init(struct pci_dev *dev)
static int pci_siig_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0;
@@ -619,7 +619,7 @@ static int pci_timedia_init(struct pci_dev *dev)
static int
pci_timedia_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int bar = 0, offset = board->first_offset;
@@ -653,7 +653,7 @@ pci_timedia_setup(struct serial_private *priv,
static int
titan_400l_800l_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int bar, offset = board->first_offset;
@@ -754,7 +754,7 @@ static int pci_ni8430_init(struct pci_dev *dev)
static int
pci_ni8430_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
void __iomem *p;
unsigned long base, len;
@@ -781,7 +781,7 @@ pci_ni8430_setup(struct serial_private *priv,
static int pci_netmos_9900_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int bar;
@@ -1032,10 +1032,17 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev)
return number_uarts;
}
-static int
-pci_default_setup(struct serial_private *priv,
+static int pci_asix_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ port->bugs |= UART_BUG_PARITY;
+ return pci_default_setup(priv, board, port, idx);
+}
+
+static int pci_default_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int bar, offset = board->first_offset, maxnr;
@@ -1057,15 +1064,15 @@ pci_default_setup(struct serial_private *priv,
static int
ce4100_serial_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
int ret;
ret = setup_port(priv, port, 0, 0, board->reg_shift);
- port->iotype = UPIO_MEM32;
- port->type = PORT_XSCALE;
- port->flags = (port->flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
- port->regshift = 2;
+ port->port.iotype = UPIO_MEM32;
+ port->port.type = PORT_XSCALE;
+ port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
+ port->port.regshift = 2;
return ret;
}
@@ -1073,16 +1080,16 @@ ce4100_serial_setup(struct serial_private *priv,
static int
pci_omegapci_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_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)
+ struct uart_8250_port *port, int idx)
{
- port->flags |= UPF_NO_TXEN_TEST;
+ port->port.flags |= UPF_NO_TXEN_TEST;
printk(KERN_DEBUG "serial8250: skipping TxEn test for device "
"[%04x:%04x] subsystem [%04x:%04x]\n",
priv->dev->vendor,
@@ -1131,11 +1138,11 @@ static unsigned int kt_serial_in(struct uart_port *p, int offset)
static int kt_serial_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
- port->flags |= UPF_BUG_THRE;
- port->serial_in = kt_serial_in;
- port->handle_break = kt_handle_break;
+ port->port.flags |= UPF_BUG_THRE;
+ port->port.serial_in = kt_serial_in;
+ port->port.handle_break = kt_handle_break;
return skip_tx_en_setup(priv, board, port, idx);
}
@@ -1151,9 +1158,19 @@ static int pci_eg20t_init(struct pci_dev *dev)
static int
pci_xr17c154_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
- port->flags |= UPF_EXAR_EFR;
+ port->port.flags |= UPF_EXAR_EFR;
+ return pci_default_setup(priv, board, port, idx);
+}
+
+static int
+pci_wch_ch353_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ port->port.flags |= UPF_FIXED_TYPE;
+ port->port.type = PORT_16550A;
return pci_default_setup(priv, board, port, idx);
}
@@ -1164,6 +1181,8 @@ pci_xr17c154_setup(struct serial_private *priv,
#define PCI_SUBDEVICE_ID_OCTPRO422 0x0208
#define PCI_SUBDEVICE_ID_POCTAL232 0x0308
#define PCI_SUBDEVICE_ID_POCTAL422 0x0408
+#define PCI_SUBDEVICE_ID_SIIG_DUAL_00 0x2500
+#define PCI_SUBDEVICE_ID_SIIG_DUAL_30 0x2530
#define PCI_VENDOR_ID_ADVANTECH 0x13fe
#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66
#define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620
@@ -1187,6 +1206,13 @@ pci_xr17c154_setup(struct serial_private *priv,
#define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6
#define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001
#define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d
+#define PCI_VENDOR_ID_WCH 0x4348
+#define PCI_DEVICE_ID_WCH_CH353_4S 0x3453
+#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046
+#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053
+#define PCI_VENDOR_ID_AGESTAR 0x5372
+#define PCI_DEVICE_ID_AGESTAR_9375 0x6872
+#define PCI_VENDOR_ID_ASIX 0x9710
/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
@@ -1726,7 +1752,41 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_omegapci_setup,
- },
+ },
+ /* WCH CH353 2S1P card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH353_2S1P,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
+ /* WCH CH353 4S card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH353_4S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
+ /* WCH CH353 2S1PF card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH353_2S1PF,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
+ /*
+ * ASIX devices with FIFO bug
+ */
+ {
+ .vendor = PCI_VENDOR_ID_ASIX,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_asix_setup,
+ },
/*
* Default "match everything" terminator entry
*/
@@ -1887,7 +1947,6 @@ enum pci_board_num_t {
pbn_panacom,
pbn_panacom2,
pbn_panacom4,
- pbn_exsys_4055,
pbn_plx_romulus,
pbn_oxsemi,
pbn_oxsemi_1_4000000,
@@ -2393,13 +2452,6 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.reg_shift = 7,
},
- [pbn_exsys_4055] = {
- .flags = FL_BASE2,
- .num_ports = 4,
- .base_baud = 115200,
- .uart_offset = 8,
- },
-
/* I think this entry is broken - the first_offset looks wrong --rmk */
[pbn_plx_romulus] = {
.flags = FL_BASE2,
@@ -2624,10 +2676,14 @@ static struct pciserial_board pci_boards[] __devinitdata = {
},
};
-static const struct pci_device_id softmodem_blacklist[] = {
+static const struct pci_device_id blacklist[] = {
+ /* softmodems */
{ PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */
{ PCI_VDEVICE(MOTOROLA, 0x3052), }, /* Motorola Si3052-based modem */
{ PCI_DEVICE(0x1543, 0x3052), }, /* Si3052-based modem, default IDs */
+
+ /* multi-io cards handled by parport_serial */
+ { PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */
};
/*
@@ -2638,7 +2694,7 @@ static const struct pci_device_id softmodem_blacklist[] = {
static int __devinit
serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
{
- const struct pci_device_id *blacklist;
+ const struct pci_device_id *bldev;
int num_iomem, num_port, first_port = -1, i;
/*
@@ -2655,13 +2711,13 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
/*
* Do not access blacklisted devices that are known not to
- * feature serial ports.
+ * feature serial ports or are handled by other modules.
*/
- for (blacklist = softmodem_blacklist;
- blacklist < softmodem_blacklist + ARRAY_SIZE(softmodem_blacklist);
- blacklist++) {
- if (dev->vendor == blacklist->vendor &&
- dev->device == blacklist->device)
+ for (bldev = blacklist;
+ bldev < blacklist + ARRAY_SIZE(blacklist);
+ bldev++) {
+ if (dev->vendor == bldev->vendor &&
+ dev->device == bldev->device)
return -ENODEV;
}
@@ -2728,7 +2784,7 @@ serial_pci_matches(const struct pciserial_board *board,
struct serial_private *
pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
{
- struct uart_port serial_port;
+ struct uart_8250_port uart;
struct serial_private *priv;
struct pci_serial_quirk *quirk;
int rc, nr_ports, i;
@@ -2768,22 +2824,22 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
priv->dev = dev;
priv->quirk = quirk;
- memset(&serial_port, 0, sizeof(struct uart_port));
- serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
- serial_port.uartclk = board->base_baud * 16;
- serial_port.irq = get_pci_irq(dev, board);
- serial_port.dev = &dev->dev;
+ memset(&uart, 0, sizeof(uart));
+ uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+ uart.port.uartclk = board->base_baud * 16;
+ uart.port.irq = get_pci_irq(dev, board);
+ uart.port.dev = &dev->dev;
for (i = 0; i < nr_ports; i++) {
- if (quirk->setup(priv, board, &serial_port, i))
+ if (quirk->setup(priv, board, &uart, i))
break;
#ifdef SERIAL_DEBUG_PCI
printk(KERN_DEBUG "Setup PCI port: port %lx, irq %d, type %d\n",
- serial_port.iobase, serial_port.irq, serial_port.iotype);
+ uart.port.iobase, uart.port.irq, uart.port.iotype);
#endif
- priv->line[i] = serial8250_register_port(&serial_port);
+ priv->line[i] = serial8250_register_8250_port(&uart);
if (priv->line[i] < 0) {
printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]);
break;
@@ -3193,7 +3249,7 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
PCI_SUBVENDOR_ID_EXSYS,
PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0,
- pbn_exsys_4055 },
+ pbn_b2_4_115200 },
/*
* Megawolf Romulus PCI Serial Card, from Mike Hudson
* (Exoray@isys.ca)
@@ -3232,8 +3288,11 @@ static struct pci_device_id serial_pci_tbl[] = {
* For now just used the hex ID 0x950a.
*/
{ PCI_VENDOR_ID_OXSEMI, 0x950a,
- PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL, 0, 0,
- pbn_b0_2_115200 },
+ PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_00,
+ 0, 0, pbn_b0_2_115200 },
+ { PCI_VENDOR_ID_OXSEMI, 0x950a,
+ PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_30,
+ 0, 0, pbn_b0_2_115200 },
{ PCI_VENDOR_ID_OXSEMI, 0x950a,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_2_1130000 },
@@ -4179,6 +4238,25 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_omegapci },
/*
+ * AgeStar as-prs2-009
+ */
+ { PCI_VENDOR_ID_AGESTAR, PCI_DEVICE_ID_AGESTAR_9375,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_b0_bt_2_115200 },
+
+ /*
+ * WCH CH353 series devices: The 2S1P is handled by parport_serial
+ * so not listed here.
+ */
+ { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_4S,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_b0_bt_4_115200 },
+
+ { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_2S1PF,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_b0_bt_2_115200 },
+
+ /*
* These entries match devices with class COMMUNICATION_SERIAL,
* COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
*/
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index a2f236510ff1..f8ee25001dd0 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -1,5 +1,5 @@
/*
- * Probe module for 8250/16550-type ISAPNP serial ports.
+ * Probe for 8250/16550-type ISAPNP serial ports.
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
*
@@ -25,7 +25,7 @@
#include "8250.h"
#define UNKNOWN_DEV 0x3000
-
+#define CIR_PORT 0x0800
static const struct pnp_device_id pnp_dev_table[] = {
/* Archtek America Corp. */
@@ -362,6 +362,9 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "PNPCXXX", UNKNOWN_DEV },
/* More unknown PnP modems */
{ "PNPDXXX", UNKNOWN_DEV },
+ /* Winbond CIR port, should not be probed. We should keep track
+ of it to prevent the legacy serial driver from probing it */
+ { "WEC1022", CIR_PORT },
{ "", 0 }
};
@@ -409,7 +412,7 @@ static int __devinit check_resources(struct pnp_dev *dev)
* PnP modems, alternatively we must hardcode all modems in pnp_devices[]
* table.
*/
-static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
+static int __devinit serial_pnp_guess_board(struct pnp_dev *dev)
{
if (!(check_name(pnp_dev_name(dev)) ||
(dev->card && check_name(dev->card->name))))
@@ -424,42 +427,49 @@ static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
static int __devinit
serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
{
- struct uart_port port;
+ struct uart_8250_port uart;
int ret, line, flags = dev_id->driver_data;
if (flags & UNKNOWN_DEV) {
- ret = serial_pnp_guess_board(dev, &flags);
+ ret = serial_pnp_guess_board(dev);
if (ret < 0)
return ret;
}
- memset(&port, 0, sizeof(struct uart_port));
+ memset(&uart, 0, sizeof(uart));
if (pnp_irq_valid(dev, 0))
- port.irq = pnp_irq(dev, 0);
- if (pnp_port_valid(dev, 0)) {
- port.iobase = pnp_port_start(dev, 0);
- port.iotype = UPIO_PORT;
+ uart.port.irq = pnp_irq(dev, 0);
+ if ((flags & CIR_PORT) && pnp_port_valid(dev, 2)) {
+ uart.port.iobase = pnp_port_start(dev, 2);
+ uart.port.iotype = UPIO_PORT;
+ } else if (pnp_port_valid(dev, 0)) {
+ uart.port.iobase = pnp_port_start(dev, 0);
+ uart.port.iotype = UPIO_PORT;
} else if (pnp_mem_valid(dev, 0)) {
- port.mapbase = pnp_mem_start(dev, 0);
- port.iotype = UPIO_MEM;
- port.flags = UPF_IOREMAP;
+ uart.port.mapbase = pnp_mem_start(dev, 0);
+ uart.port.iotype = UPIO_MEM;
+ uart.port.flags = UPF_IOREMAP;
} else
return -ENODEV;
#ifdef SERIAL_DEBUG_PNP
printk(KERN_DEBUG
"Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
- port.iobase, port.mapbase, port.irq, port.iotype);
+ uart.port.iobase, uart.port.mapbase, uart.port.irq, uart.port.iotype);
#endif
+ if (flags & CIR_PORT) {
+ uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
+ uart.port.type = PORT_8250_CIR;
+ }
- port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+ uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
- port.flags |= UPF_SHARE_IRQ;
- port.uartclk = 1843200;
- port.dev = &dev->dev;
+ uart.port.flags |= UPF_SHARE_IRQ;
+ uart.port.uartclk = 1843200;
+ uart.port.dev = &dev->dev;
- line = serial8250_register_port(&port);
- if (line < 0)
+ line = serial8250_register_8250_port(&uart);
+ if (line < 0 || (flags & CIR_PORT))
return -ENODEV;
pnp_set_drvdata(dev, (void *)((long)line + 1));
@@ -507,18 +517,13 @@ static struct pnp_driver serial_pnp_driver = {
.id_table = pnp_dev_table,
};
-static int __init serial8250_pnp_init(void)
+int serial8250_pnp_init(void)
{
return pnp_register_driver(&serial_pnp_driver);
}
-static void __exit serial8250_pnp_exit(void)
+void serial8250_pnp_exit(void)
{
pnp_unregister_driver(&serial_pnp_driver);
}
-module_init(serial8250_pnp_init);
-module_exit(serial8250_pnp_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic 8250/16x50 PnP serial driver");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index a27dd0569bd7..f3d283f2e3aa 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -33,6 +33,14 @@ config SERIAL_8250
Most people will say Y or M here, so that they can use serial mice,
modems and similar devices connecting to the standard serial ports.
+config SERIAL_8250_PNP
+ bool "8250/16550 PNP device support" if EXPERT
+ depends on SERIAL_8250 && PNP
+ default y
+ ---help---
+ This builds standard PNP serial support. You may be able to
+ disable this feature if you only need legacy serial support.
+
config SERIAL_8250_CONSOLE
bool "Console on 8250/16550 and compatible serial port"
depends on SERIAL_8250=y
@@ -85,14 +93,6 @@ config SERIAL_8250_PCI
disable this feature if you only need legacy serial support.
Saves about 9K.
-config SERIAL_8250_PNP
- tristate "8250/16550 PNP device support" if EXPERT
- depends on SERIAL_8250 && PNP
- default SERIAL_8250
- help
- This builds standard PNP serial support. You may be able to
- disable this feature if you only need legacy serial support.
-
config SERIAL_8250_HP300
tristate
depends on SERIAL_8250 && HP300
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index d7533c7d2c1a..108fe7fe13e2 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -2,8 +2,9 @@
# Makefile for the 8250 serial device drivers.
#
-obj-$(CONFIG_SERIAL_8250) += 8250.o
-obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
+obj-$(CONFIG_SERIAL_8250) += 8250_core.o
+8250_core-y := 8250.o
+8250_core-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c
index 29b695d041ec..b7d48b346393 100644
--- a/drivers/tty/serial/8250/serial_cs.c
+++ b/drivers/tty/serial/8250/serial_cs.c
@@ -73,7 +73,7 @@ struct serial_quirk {
unsigned int prodid;
int multi; /* 1 = multifunction, > 1 = # ports */
void (*config)(struct pcmcia_device *);
- void (*setup)(struct pcmcia_device *, struct uart_port *);
+ void (*setup)(struct pcmcia_device *, struct uart_8250_port *);
void (*wakeup)(struct pcmcia_device *);
int (*post)(struct pcmcia_device *);
};
@@ -105,9 +105,9 @@ struct serial_cfg_mem {
* Elan VPU16551 UART with 14.7456MHz oscillator
* manfid 0x015D, 0x4C45
*/
-static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_port *port)
+static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_8250_port *uart)
{
- port->uartclk = 14745600;
+ uart->port.uartclk = 14745600;
}
static int quirk_post_ibm(struct pcmcia_device *link)
@@ -343,25 +343,25 @@ static void serial_detach(struct pcmcia_device *link)
static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
unsigned int iobase, int irq)
{
- struct uart_port port;
+ struct uart_8250_port uart;
int line;
- memset(&port, 0, sizeof (struct uart_port));
- port.iobase = iobase;
- port.irq = irq;
- port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
- port.uartclk = 1843200;
- port.dev = &handle->dev;
+ memset(&uart, 0, sizeof(uart));
+ uart.port.iobase = iobase;
+ uart.port.irq = irq;
+ uart.port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+ uart.port.uartclk = 1843200;
+ uart.port.dev = &handle->dev;
if (buggy_uart)
- port.flags |= UPF_BUGGY_UART;
+ uart.port.flags |= UPF_BUGGY_UART;
if (info->quirk && info->quirk->setup)
- info->quirk->setup(handle, &port);
+ info->quirk->setup(handle, &uart);
- line = serial8250_register_port(&port);
+ line = serial8250_register_8250_port(&uart);
if (line < 0) {
- printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
- "0x%04lx, irq %d failed\n", (u_long)iobase, irq);
+ pr_err("serial_cs: serial8250_register_8250_port() at 0x%04lx, irq %d failed\n",
+ (unsigned long)iobase, irq);
return -EINVAL;
}
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 4720b4ba096a..233fbaaf2559 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -141,6 +141,25 @@ config SERIAL_ATMEL_TTYAT
Say Y if you have an external 8250/16C550 UART. If unsure, say N.
+config SERIAL_KGDB_NMI
+ bool "Serial console over KGDB NMI debugger port"
+ depends on KGDB_SERIAL_CONSOLE
+ help
+ This special driver allows you to temporary use NMI debugger port
+ as a normal console (assuming that the port is attached to KGDB).
+
+ Unlike KDB's disable_nmi command, with this driver you are always
+ able to go back to the debugger using KGDB escape sequence ($3#33).
+ This is because this console driver processes the input in NMI
+ context, and thus is able to intercept the magic sequence.
+
+ Note that since the console interprets input and uses polling
+ communication methods, for things like PPP you still must fully
+ detach debugger port from the KGDB NMI (i.e. disable_nmi), and
+ use raw console.
+
+ If unsure, say N.
+
config SERIAL_KS8695
bool "Micrel KS8695 (Centaur) serial port support"
depends on ARCH_KS8695
@@ -257,12 +276,19 @@ config SERIAL_MAX3100
help
MAX3100 chip support
-config SERIAL_MAX3107
- tristate "MAX3107 support"
+config SERIAL_MAX310X
+ bool "MAX310X support"
depends on SPI
select SERIAL_CORE
+ select REGMAP_SPI if SPI
+ default n
help
- MAX3107 chip support
+ This selects support for an advanced UART from Maxim (Dallas).
+ Supported ICs are MAX3107, MAX3108.
+ Each IC contains 128 words each of receive and transmit FIFO
+ that can be controlled through I2C or high-speed SPI.
+
+ Say Y here if you want to support this ICs.
config SERIAL_DZ
bool "DECstation DZ serial driver"
@@ -686,7 +712,7 @@ config SERIAL_SH_SCI_CONSOLE
config SERIAL_SH_SCI_DMA
bool "DMA support"
- depends on SERIAL_SH_SCI && SH_DMAE && EXPERIMENTAL
+ depends on SERIAL_SH_SCI && SH_DMAE
config SERIAL_PNX8XXX
bool "Enable PNX8XXX SoCs' UART Support"
@@ -704,6 +730,25 @@ config SERIAL_PNX8XXX_CONSOLE
If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
and you want to use serial console, say Y. Otherwise, say N.
+config SERIAL_HS_LPC32XX
+ tristate "LPC32XX high speed serial port support"
+ depends on ARCH_LPC32XX && OF
+ select SERIAL_CORE
+ help
+ Support for the LPC32XX high speed serial ports (up to 900kbps).
+ Those are UARTs completely different from the Standard UARTs on the
+ LPC32XX SoC.
+ Choose M or Y here to build this driver.
+
+config SERIAL_HS_LPC32XX_CONSOLE
+ bool "Enable LPC32XX high speed UART serial console"
+ depends on SERIAL_HS_LPC32XX
+ select SERIAL_CORE_CONSOLE
+ help
+ If you would like to be able to use one of the high speed serial
+ ports on the LPC32XX as the console, you can do so by answering
+ Y to this option.
+
config SERIAL_CORE
tristate
@@ -1104,6 +1149,24 @@ config SERIAL_SC26XX_CONSOLE
help
Support for Console on SC2681/SC2692 serial ports.
+config SERIAL_SCCNXP
+ bool "SCCNXP serial port support"
+ depends on !SERIAL_SC26XX
+ select SERIAL_CORE
+ default n
+ help
+ This selects support for an advanced UART from NXP (Philips).
+ Supported ICs are SCC2681, SCC2691, SCC2692, SC28L91, SC28L92,
+ SC28L202, SCC68681 and SCC68692.
+ Positioned as a replacement for the driver SC26XX.
+
+config SERIAL_SCCNXP_CONSOLE
+ bool "Console on SCCNXP serial port"
+ depends on SERIAL_SCCNXP
+ select SERIAL_CORE_CONSOLE
+ help
+ Support for console on SCCNXP serial ports.
+
config SERIAL_BFIN_SPORT
tristate "Blackfin SPORT emulate UART"
depends on BLACKFIN
@@ -1260,7 +1323,7 @@ config SERIAL_ALTERA_UART_CONSOLE
config SERIAL_IFX6X60
tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
- depends on GPIOLIB && SPI && EXPERIMENTAL
+ depends on GPIOLIB && SPI
help
Support for the IFX6x60 modem devices on Intel MID platforms.
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 7257c5d898ae..4f694dafa719 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -28,12 +28,13 @@ obj-$(CONFIG_SERIAL_BFIN) += bfin_uart.o
obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o
obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o
obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
-obj-$(CONFIG_SERIAL_MAX3107) += max3107.o
+obj-$(CONFIG_SERIAL_MAX310X) += max310x.o
obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
obj-$(CONFIG_SERIAL_MUX) += mux.o
obj-$(CONFIG_SERIAL_68328) += 68328serial.o
obj-$(CONFIG_SERIAL_MCF) += mcf.o
obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
+obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o
obj-$(CONFIG_SERIAL_DZ) += dz.o
obj-$(CONFIG_SERIAL_ZS) += zs.o
obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
@@ -47,6 +48,7 @@ obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o
+obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
obj-$(CONFIG_SERIAL_JSM) += jsm/
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
@@ -59,6 +61,7 @@ obj-$(CONFIG_SERIAL_MSM_HS) += msm_serial_hs.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
+obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 1f0330915d5a..15d80b9fb303 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -591,7 +591,7 @@ 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);
+ platform_set_drvdata(pdev, port);
uart_add_one_port(&altera_uart_driver, port);
@@ -600,11 +600,11 @@ static int __devinit altera_uart_probe(struct platform_device *pdev)
static int __devexit altera_uart_remove(struct platform_device *pdev)
{
- struct uart_port *port = dev_get_drvdata(&pdev->dev);
+ struct uart_port *port = platform_get_drvdata(pdev);
if (port) {
uart_remove_one_port(&altera_uart_driver, port);
- dev_set_drvdata(&pdev->dev, NULL);
+ platform_set_drvdata(pdev, NULL);
port->mapbase = 0;
}
diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c
index 0d91a540bf11..22317dd16474 100644
--- a/drivers/tty/serial/amba-pl010.c
+++ b/drivers/tty/serial/amba-pl010.c
@@ -312,16 +312,12 @@ static int pl010_startup(struct uart_port *port)
struct uart_amba_port *uap = (struct uart_amba_port *)port;
int retval;
- retval = clk_prepare(uap->clk);
- if (retval)
- goto out;
-
/*
* Try to enable the clock producer.
*/
- retval = clk_enable(uap->clk);
+ retval = clk_prepare_enable(uap->clk);
if (retval)
- goto clk_unprep;
+ goto out;
uap->port.uartclk = clk_get_rate(uap->clk);
@@ -346,9 +342,7 @@ static int pl010_startup(struct uart_port *port)
return 0;
clk_dis:
- clk_disable(uap->clk);
- clk_unprep:
- clk_unprepare(uap->clk);
+ clk_disable_unprepare(uap->clk);
out:
return retval;
}
@@ -375,8 +369,7 @@ static void pl010_shutdown(struct uart_port *port)
/*
* Shut down the clock producer
*/
- clk_disable(uap->clk);
- clk_unprepare(uap->clk);
+ clk_disable_unprepare(uap->clk);
}
static void
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index d3553b5d3fca..d7e1edec50b5 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -52,6 +52,8 @@
#include <linux/scatterlist.h>
#include <linux/delay.h>
#include <linux/types.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/sizes.h>
@@ -75,7 +77,6 @@ struct vendor_data {
unsigned int lcrh_tx;
unsigned int lcrh_rx;
bool oversampling;
- bool interrupt_may_hang; /* vendor-specific */
bool dma_threshold;
bool cts_event_workaround;
};
@@ -96,7 +97,6 @@ static struct vendor_data vendor_st = {
.lcrh_tx = ST_UART011_LCRH_TX,
.lcrh_rx = ST_UART011_LCRH_RX,
.oversampling = true,
- .interrupt_may_hang = true,
.dma_threshold = true,
.cts_event_workaround = true,
};
@@ -147,7 +147,6 @@ struct uart_amba_port {
unsigned int old_cr; /* state during shutdown */
bool autorts;
char type[12];
- bool interrupt_may_hang; /* vendor-specific */
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
bool using_tx_dma;
@@ -1215,14 +1214,14 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
return IRQ_RETVAL(handled);
}
-static unsigned int pl01x_tx_empty(struct uart_port *port)
+static unsigned int pl011_tx_empty(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int status = readw(uap->port.membase + UART01x_FR);
return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
}
-static unsigned int pl01x_get_mctrl(struct uart_port *port)
+static unsigned int pl011_get_mctrl(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int result = 0;
@@ -1285,11 +1284,40 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
}
#ifdef CONFIG_CONSOLE_POLL
-static int pl010_get_poll_char(struct uart_port *port)
+
+static void pl011_quiesce_irqs(struct uart_port *port)
+{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ unsigned char __iomem *regs = uap->port.membase;
+
+ writew(readw(regs + UART011_MIS), regs + UART011_ICR);
+ /*
+ * There is no way to clear TXIM as this is "ready to transmit IRQ", so
+ * we simply mask it. start_tx() will unmask it.
+ *
+ * Note we can race with start_tx(), and if the race happens, the
+ * polling user might get another interrupt just after we clear it.
+ * But it should be OK and can happen even w/o the race, e.g.
+ * controller immediately got some new data and raised the IRQ.
+ *
+ * And whoever uses polling routines assumes that it manages the device
+ * (including tx queue), so we're also fine with start_tx()'s caller
+ * side.
+ */
+ writew(readw(regs + UART011_IMSC) & ~UART011_TXIM, regs + UART011_IMSC);
+}
+
+static int pl011_get_poll_char(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int status;
+ /*
+ * The caller might need IRQs lowered, e.g. if used with KDB NMI
+ * debugger.
+ */
+ pl011_quiesce_irqs(port);
+
status = readw(uap->port.membase + UART01x_FR);
if (status & UART01x_FR_RXFE)
return NO_POLL_CHAR;
@@ -1297,7 +1325,7 @@ static int pl010_get_poll_char(struct uart_port *port)
return readw(uap->port.membase + UART01x_DR);
}
-static void pl010_put_poll_char(struct uart_port *port,
+static void pl011_put_poll_char(struct uart_port *port,
unsigned char ch)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1310,10 +1338,9 @@ static void pl010_put_poll_char(struct uart_port *port,
#endif /* CONFIG_CONSOLE_POLL */
-static int pl011_startup(struct uart_port *port)
+static int pl011_hwinit(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
- unsigned int cr;
int retval;
/* Optionaly enable pins to be muxed in and configured */
@@ -1324,16 +1351,12 @@ static int pl011_startup(struct uart_port *port)
"could not set default pins\n");
}
- retval = clk_prepare(uap->clk);
- if (retval)
- goto out;
-
/*
* Try to enable the clock producer.
*/
- retval = clk_enable(uap->clk);
+ retval = clk_prepare_enable(uap->clk);
if (retval)
- goto clk_unprep;
+ goto out;
uap->port.uartclk = clk_get_rate(uap->clk);
@@ -1342,6 +1365,37 @@ static int pl011_startup(struct uart_port *port)
UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
/*
+ * Save interrupts enable mask, and enable RX interrupts in case if
+ * the interrupt is used for NMI entry.
+ */
+ uap->im = readw(uap->port.membase + UART011_IMSC);
+ writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+
+ if (uap->port.dev->platform_data) {
+ struct amba_pl011_data *plat;
+
+ plat = uap->port.dev->platform_data;
+ if (plat->init)
+ plat->init();
+ }
+ return 0;
+ out:
+ return retval;
+}
+
+static int pl011_startup(struct uart_port *port)
+{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ unsigned int cr;
+ int retval;
+
+ retval = pl011_hwinit(port);
+ if (retval)
+ goto clk_dis;
+
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+
+ /*
* Allocate the IRQ
*/
retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
@@ -1400,21 +1454,10 @@ static int pl011_startup(struct uart_port *port)
writew(uap->im, uap->port.membase + UART011_IMSC);
spin_unlock_irq(&uap->port.lock);
- if (uap->port.dev->platform_data) {
- struct amba_pl011_data *plat;
-
- plat = uap->port.dev->platform_data;
- if (plat->init)
- plat->init();
- }
-
return 0;
clk_dis:
- clk_disable(uap->clk);
- clk_unprep:
- clk_unprepare(uap->clk);
- out:
+ clk_disable_unprepare(uap->clk);
return retval;
}
@@ -1473,8 +1516,7 @@ static void pl011_shutdown(struct uart_port *port)
/*
* Shut down the clock producer
*/
- clk_disable(uap->clk);
- clk_unprepare(uap->clk);
+ clk_disable_unprepare(uap->clk);
/* Optionally let pins go into sleep states */
if (!IS_ERR(uap->pins_sleep)) {
retval = pinctrl_select_state(uap->pinctrl, uap->pins_sleep);
@@ -1603,13 +1645,26 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
old_cr &= ~ST_UART011_CR_OVSFACT;
}
+ /*
+ * Workaround for the ST Micro oversampling variants to
+ * increase the bitrate slightly, by lowering the divisor,
+ * to avoid delayed sampling of start bit at high speeds,
+ * else we see data corruption.
+ */
+ if (uap->vendor->oversampling) {
+ if ((baud >= 3000000) && (baud < 3250000) && (quot > 1))
+ quot -= 1;
+ else if ((baud > 3250000) && (quot > 2))
+ quot -= 2;
+ }
/* Set baud rate */
writew(quot & 0x3f, port->membase + UART011_FBRD);
writew(quot >> 6, port->membase + UART011_IBRD);
/*
* ----------v----------v----------v----------v-----
- * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
+ * NOTE: lcrh_tx and lcrh_rx MUST BE WRITTEN AFTER
+ * UART011_FBRD & UART011_IBRD.
* ----------^----------^----------^----------^-----
*/
writew(lcr_h, port->membase + uap->lcrh_rx);
@@ -1637,7 +1692,7 @@ static const char *pl011_type(struct uart_port *port)
/*
* Release the memory region(s) being used by 'port'
*/
-static void pl010_release_port(struct uart_port *port)
+static void pl011_release_port(struct uart_port *port)
{
release_mem_region(port->mapbase, SZ_4K);
}
@@ -1645,7 +1700,7 @@ static void pl010_release_port(struct uart_port *port)
/*
* Request the memory region(s) being used by 'port'
*/
-static int pl010_request_port(struct uart_port *port)
+static int pl011_request_port(struct uart_port *port)
{
return request_mem_region(port->mapbase, SZ_4K, "uart-pl011")
!= NULL ? 0 : -EBUSY;
@@ -1654,18 +1709,18 @@ static int pl010_request_port(struct uart_port *port)
/*
* Configure/autoconfigure the port.
*/
-static void pl010_config_port(struct uart_port *port, int flags)
+static void pl011_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_AMBA;
- pl010_request_port(port);
+ pl011_request_port(port);
}
}
/*
* verify the new serial_struct (for TIOCSSERIAL).
*/
-static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
+static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
{
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
@@ -1678,9 +1733,9 @@ static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
}
static struct uart_ops amba_pl011_pops = {
- .tx_empty = pl01x_tx_empty,
+ .tx_empty = pl011_tx_empty,
.set_mctrl = pl011_set_mctrl,
- .get_mctrl = pl01x_get_mctrl,
+ .get_mctrl = pl011_get_mctrl,
.stop_tx = pl011_stop_tx,
.start_tx = pl011_start_tx,
.stop_rx = pl011_stop_rx,
@@ -1691,13 +1746,14 @@ static struct uart_ops amba_pl011_pops = {
.flush_buffer = pl011_dma_flush_buffer,
.set_termios = pl011_set_termios,
.type = pl011_type,
- .release_port = pl010_release_port,
- .request_port = pl010_request_port,
- .config_port = pl010_config_port,
- .verify_port = pl010_verify_port,
+ .release_port = pl011_release_port,
+ .request_port = pl011_request_port,
+ .config_port = pl011_config_port,
+ .verify_port = pl011_verify_port,
#ifdef CONFIG_CONSOLE_POLL
- .poll_get_char = pl010_get_poll_char,
- .poll_put_char = pl010_put_poll_char,
+ .poll_init = pl011_hwinit,
+ .poll_get_char = pl011_get_poll_char,
+ .poll_put_char = pl011_put_poll_char,
#endif
};
@@ -1869,6 +1925,38 @@ static struct uart_driver amba_reg = {
.cons = AMBA_CONSOLE,
};
+static int pl011_probe_dt_alias(int index, struct device *dev)
+{
+ struct device_node *np;
+ static bool seen_dev_with_alias = false;
+ static bool seen_dev_without_alias = false;
+ int ret = index;
+
+ if (!IS_ENABLED(CONFIG_OF))
+ return ret;
+
+ np = dev->of_node;
+ if (!np)
+ return ret;
+
+ ret = of_alias_get_id(np, "serial");
+ if (IS_ERR_VALUE(ret)) {
+ seen_dev_without_alias = true;
+ ret = index;
+ } else {
+ seen_dev_with_alias = true;
+ if (ret >= ARRAY_SIZE(amba_ports) || amba_ports[ret] != NULL) {
+ dev_warn(dev, "requested serial port %d not available.\n", ret);
+ ret = index;
+ }
+ }
+
+ if (seen_dev_with_alias && seen_dev_without_alias)
+ dev_warn(dev, "aliased and non-aliased serial devices found in device tree. Serial port enumeration may be unpredictable.\n");
+
+ return ret;
+}
+
static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
{
struct uart_amba_port *uap;
@@ -1891,6 +1979,8 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
goto out;
}
+ i = pl011_probe_dt_alias(i, &dev->dev);
+
base = ioremap(dev->res.start, resource_size(&dev->res));
if (!base) {
ret = -ENOMEM;
@@ -1923,7 +2013,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
uap->lcrh_tx = vendor->lcrh_tx;
uap->old_cr = 0;
uap->fifosize = vendor->fifosize;
- uap->interrupt_may_hang = vendor->interrupt_may_hang;
uap->port.dev = &dev->dev;
uap->port.mapbase = dev->res.start;
uap->port.membase = base;
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index bd97db23985b..9242d56ba267 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -182,7 +182,7 @@ static void bfin_serial_start_tx(struct uart_port *port)
* To avoid losting RX interrupt, we reset IR function
* before sending data.
*/
- if (tty->termios->c_line == N_IRDA)
+ if (tty->termios.c_line == N_IRDA)
bfin_serial_reset_irda(port);
#ifdef CONFIG_SERIAL_BFIN_DMA
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index b418947b7107..d0dd9194cecc 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -71,7 +71,7 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo);
/**************************************************************/
-#define HW_BUF_SPD_THRESHOLD 9600
+#define HW_BUF_SPD_THRESHOLD 2400
/*
* Check, if transmit buffers are processed
@@ -417,6 +417,7 @@ static int cpm_uart_startup(struct uart_port *port)
clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR);
clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
}
+ cpm_uart_initbd(pinfo);
cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
}
/* Install interrupt handler. */
@@ -500,16 +501,28 @@ static void cpm_uart_set_termios(struct uart_port *port,
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
smc_t __iomem *smcp = pinfo->smcp;
scc_t __iomem *sccp = pinfo->sccp;
+ int maxidl;
pr_debug("CPM uart[%d]:set_termios\n", port->line);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
- if (baud <= HW_BUF_SPD_THRESHOLD ||
+ if (baud < HW_BUF_SPD_THRESHOLD ||
(pinfo->port.state && pinfo->port.state->port.tty->low_latency))
pinfo->rx_fifosize = 1;
else
pinfo->rx_fifosize = RX_BUF_SIZE;
+ /* MAXIDL is the timeout after which a receive buffer is closed
+ * when not full if no more characters are received.
+ * We calculate it from the baudrate so that the duration is
+ * always the same at standard rates: about 4ms.
+ */
+ maxidl = baud / 2400;
+ if (maxidl < 1)
+ maxidl = 1;
+ if (maxidl > 0x10)
+ maxidl = 0x10;
+
/* Character length programmed into the mode register is the
* sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
* 1 or 2 stop bits, minus 1.
@@ -610,6 +623,7 @@ static void cpm_uart_set_termios(struct uart_port *port,
* SMC/SCC receiver is disabled.
*/
out_be16(&pinfo->smcup->smc_mrblr, pinfo->rx_fifosize);
+ out_be16(&pinfo->smcup->smc_maxidl, maxidl);
/* Set the mode register. We want to keep a copy of the
* enables, because we want to put them back if they were
@@ -622,6 +636,7 @@ static void cpm_uart_set_termios(struct uart_port *port,
SMCMR_SM_UART | prev_mode);
} else {
out_be16(&pinfo->sccup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
+ out_be16(&pinfo->sccup->scc_maxidl, maxidl);
out_be16(&sccp->scc_psmr, (sbits << 12) | scval);
}
@@ -798,7 +813,7 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo)
cpm_set_scc_fcr(sup);
out_be16(&sup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
- out_be16(&sup->scc_maxidl, pinfo->rx_fifosize);
+ out_be16(&sup->scc_maxidl, 0x10);
out_be16(&sup->scc_brkcr, 1);
out_be16(&sup->scc_parec, 0);
out_be16(&sup->scc_frmec, 0);
@@ -872,7 +887,7 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
/* Using idle character time requires some additional tuning. */
out_be16(&up->smc_mrblr, pinfo->rx_fifosize);
- out_be16(&up->smc_maxidl, pinfo->rx_fifosize);
+ out_be16(&up->smc_maxidl, 0x10);
out_be16(&up->smc_brklen, 0);
out_be16(&up->smc_brkec, 0);
out_be16(&up->smc_brkcr, 1);
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index 80b6b1b1f725..35ee6a2c6877 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -955,7 +955,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
/* Calculate the chartime depending on baudrate, numbor of bits etc. */
static void update_char_time(struct e100_serial * info)
{
- tcflag_t cflags = info->port.tty->termios->c_cflag;
+ tcflag_t cflags = info->port.tty->termios.c_cflag;
int bits;
/* calc. number of bits / data byte */
@@ -1473,7 +1473,7 @@ rs_stop(struct tty_struct *tty)
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char,
STOP_CHAR(info->port.tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
- if (tty->termios->c_iflag & IXON ) {
+ if (tty->termios.c_iflag & IXON ) {
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
}
@@ -1496,7 +1496,7 @@ rs_start(struct tty_struct *tty)
info->xmit.tail,SERIAL_XMIT_SIZE)));
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
- if (tty->termios->c_iflag & IXON ) {
+ if (tty->termios.c_iflag & IXON ) {
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
}
@@ -2929,7 +2929,7 @@ shutdown(struct e100_serial * info)
descr[i].buf = 0;
}
- if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
+ if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) {
/* hang up DTR and RTS if HUPCL is enabled */
e100_dtr(info, 0);
e100_rts(info, 0); /* could check CRTSCTS before doing this */
@@ -2953,12 +2953,12 @@ change_speed(struct e100_serial *info)
unsigned long flags;
/* first some safety checks */
- if (!info->port.tty || !info->port.tty->termios)
+ if (!info->port.tty)
return;
if (!info->ioport)
return;
- cflag = info->port.tty->termios->c_cflag;
+ cflag = info->port.tty->termios.c_cflag;
/* possibly, the tx/rx should be disabled first to do this safely */
@@ -3088,7 +3088,7 @@ change_speed(struct e100_serial *info)
info->ioport[REG_REC_CTRL] = info->rx_ctrl;
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
- if (info->port.tty->termios->c_iflag & IXON ) {
+ if (info->port.tty->termios.c_iflag & IXON ) {
DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n",
STOP_CHAR(info->port.tty)));
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
@@ -3355,7 +3355,7 @@ rs_throttle(struct tty_struct * tty)
DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
/* Do RTS before XOFF since XOFF might take some time */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
/* Turn off RTS line */
e100_rts(info, 0);
}
@@ -3377,7 +3377,7 @@ rs_unthrottle(struct tty_struct * tty)
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count));
/* Do RTS before XOFF since XOFF might take some time */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
/* Assert RTS line */
e100_rts(info, 1);
}
@@ -3748,7 +3748,7 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
rs_start(tty);
}
@@ -3815,7 +3815,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
* separate termios for callout and dialin.
*/
if (info->flags & ASYNC_NORMAL_ACTIVE)
- info->normal_termios = *tty->termios;
+ info->normal_termios = tty->termios;
/*
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
@@ -3976,7 +3976,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
*/
if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) {
- wait_event_interruptible_tty(info->close_wait,
+ wait_event_interruptible_tty(tty, info->close_wait,
!(info->flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART
if (info->flags & ASYNC_HUP_NOTIFY)
@@ -3998,7 +3998,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
return 0;
}
- if (tty->termios->c_cflag & CLOCAL) {
+ if (tty->termios.c_cflag & CLOCAL) {
do_clocal = 1;
}
@@ -4052,9 +4052,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
printk("block_til_ready blocking: ttyS%d, count = %d\n",
info->line, info->count);
#endif
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
@@ -4115,7 +4115,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
*/
if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) {
- wait_event_interruptible_tty(info->close_wait,
+ wait_event_interruptible_tty(tty, info->close_wait,
!(info->flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART
return ((info->flags & ASYNC_HUP_NOTIFY) ?
@@ -4219,7 +4219,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
}
if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
- *tty->termios = info->normal_termios;
+ tty->termios = info->normal_termios;
change_speed(info);
}
@@ -4443,14 +4443,12 @@ static int __init rs_init(void)
B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
driver->init_termios.c_ispeed = 115200;
driver->init_termios.c_ospeed = 115200;
- driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(driver, &rs_ops);
serial_driver = driver;
- if (tty_register_driver(driver))
- panic("Couldn't register serial driver\n");
- /* do some initializing for the separate ports */
+ /* do some initializing for the separate ports */
for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
if (info->enabled) {
if (cris_request_io_interface(info->io_if,
@@ -4502,7 +4500,12 @@ static int __init rs_init(void)
printk(KERN_INFO "%s%d at %p is a builtin UART with DMA\n",
serial_driver->name, info->line, info->ioport);
}
+ tty_port_link_device(&info->port, driver, i);
}
+
+ if (tty_register_driver(driver))
+ panic("Couldn't register serial driver\n");
+
#ifdef CONFIG_ETRAX_FAST_TIMER
#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
memset(fast_timers, 0, sizeof(fast_timers));
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index 3ad079ffd049..5b9bc19ed134 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -800,8 +800,8 @@ static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev)
tty_port_init(pport);
pport->ops = &ifx_tty_port_ops;
ifx_dev->minor = IFX_SPI_TTY_ID;
- ifx_dev->tty_dev = tty_register_device(tty_drv, ifx_dev->minor,
- &ifx_dev->spi_dev->dev);
+ ifx_dev->tty_dev = tty_port_register_device(pport, tty_drv,
+ ifx_dev->minor, &ifx_dev->spi_dev->dev);
if (IS_ERR(ifx_dev->tty_dev)) {
dev_dbg(&ifx_dev->spi_dev->dev,
"%s: registering tty device failed", __func__);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index e309e8b0aaba..efeb8becfa43 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -207,7 +207,7 @@ struct imx_port {
unsigned short trcv_delay; /* transceiver delay */
struct clk *clk_ipg;
struct clk *clk_per;
- struct imx_uart_data *devdata;
+ const struct imx_uart_data *devdata;
};
struct imx_port_ucrs {
@@ -1373,8 +1373,7 @@ static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
val |= UCR3_AWAKEN;
writel(val, sport->port.membase + UCR3);
- if (sport)
- uart_suspend_port(&imx_reg, &sport->port);
+ uart_suspend_port(&imx_reg, &sport->port);
return 0;
}
@@ -1389,8 +1388,7 @@ static int serial_imx_resume(struct platform_device *dev)
val &= ~UCR3_AWAKEN;
writel(val, sport->port.membase + UCR3);
- if (sport)
- uart_resume_port(&imx_reg, &sport->port);
+ uart_resume_port(&imx_reg, &sport->port);
return 0;
}
@@ -1505,18 +1503,21 @@ static int serial_imx_probe(struct platform_device *pdev)
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl)) {
ret = PTR_ERR(pinctrl);
+ dev_err(&pdev->dev, "failed to get default pinctrl: %d\n", ret);
goto unmap;
}
sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(sport->clk_ipg)) {
ret = PTR_ERR(sport->clk_ipg);
+ dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret);
goto unmap;
}
sport->clk_per = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(sport->clk_per)) {
ret = PTR_ERR(sport->clk_per);
+ dev_err(&pdev->dev, "failed to get per clk: %d\n", ret);
goto unmap;
}
@@ -1537,7 +1538,7 @@ static int serial_imx_probe(struct platform_device *pdev)
ret = uart_add_one_port(&imx_reg, &sport->port);
if (ret)
goto deinit;
- platform_set_drvdata(pdev, &sport->port);
+ platform_set_drvdata(pdev, sport);
return 0;
deinit:
diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c
index 758ff310f7f8..5ac52898a0bb 100644
--- a/drivers/tty/serial/ioc3_serial.c
+++ b/drivers/tty/serial/ioc3_serial.c
@@ -1120,13 +1120,14 @@ static inline int do_read(struct uart_port *the_port, char *buf, int len)
struct ioc3_port *port = get_ioc3_port(the_port);
struct ring *inring;
struct ring_entry *entry;
- struct port_hooks *hooks = port->ip_hooks;
+ struct port_hooks *hooks;
int byte_num;
char *sc;
int loop_counter;
BUG_ON(!(len >= 0));
BUG_ON(!port);
+ hooks = port->ip_hooks;
/* There is a nasty timing issue in the IOC3. When the rx_timer
* expires or the rx_high condition arises, we take an interrupt.
diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c
index e16894fb2ca3..3e7da10cebba 100644
--- a/drivers/tty/serial/ioc4_serial.c
+++ b/drivers/tty/serial/ioc4_serial.c
@@ -1803,7 +1803,7 @@ static inline int ic4_startup_local(struct uart_port *the_port)
ioc4_set_proto(port, the_port->mapbase);
/* set the speed of the serial port */
- ioc4_change_speed(the_port, state->port.tty->termios,
+ ioc4_change_speed(the_port, &state->port.tty->termios,
(struct ktermios *)0);
return 0;
@@ -2069,13 +2069,14 @@ static inline int do_read(struct uart_port *the_port, unsigned char *buf,
struct ioc4_port *port = get_ioc4_port(the_port, 0);
struct ring *inring;
struct ring_entry *entry;
- struct hooks *hooks = port->ip_hooks;
+ struct hooks *hooks;
int byte_num;
char *sc;
int loop_counter;
BUG_ON(!(len >= 0));
BUG_ON(!port);
+ hooks = port->ip_hooks;
/* There is a nasty timing issue in the IOC4. When the rx_timer
* expires or the rx_high condition arises, we take an interrupt.
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
index 434bd881fcae..71397961773c 100644
--- a/drivers/tty/serial/jsm/jsm_tty.c
+++ b/drivers/tty/serial/jsm/jsm_tty.c
@@ -161,7 +161,7 @@ static void jsm_tty_send_xchar(struct uart_port *port, char ch)
struct ktermios *termios;
spin_lock_irqsave(&port->lock, lock_flags);
- termios = port->state->port.tty->termios;
+ termios = &port->state->port.tty->termios;
if (ch == termios->c_cc[VSTART])
channel->ch_bd->bd_ops->send_start_character(channel);
@@ -250,7 +250,7 @@ static int jsm_tty_open(struct uart_port *port)
channel->ch_cached_lsr = 0;
channel->ch_stops_sent = 0;
- termios = port->state->port.tty->termios;
+ termios = &port->state->port.tty->termios;
channel->ch_c_cflag = termios->c_cflag;
channel->ch_c_iflag = termios->c_iflag;
channel->ch_c_oflag = termios->c_oflag;
@@ -283,7 +283,7 @@ static void jsm_tty_close(struct uart_port *port)
jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n");
bd = channel->ch_bd;
- ts = port->state->port.tty->termios;
+ ts = &port->state->port.tty->termios;
channel->ch_flags &= ~(CH_STOPI);
@@ -567,7 +567,7 @@ void jsm_input(struct jsm_channel *ch)
*input data and return immediately.
*/
if (!tp ||
- !(tp->termios->c_cflag & CREAD) ) {
+ !(tp->termios.c_cflag & CREAD) ) {
jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
"input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum);
diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
new file mode 100644
index 000000000000..d185247ba1aa
--- /dev/null
+++ b/drivers/tty/serial/kgdb_nmi.c
@@ -0,0 +1,402 @@
+/*
+ * KGDB NMI serial console
+ *
+ * Copyright 2010 Google, Inc.
+ * Arve Hjønnevåg <arve@android.com>
+ * Colin Cross <ccross@android.com>
+ * Copyright 2012 Linaro Ltd.
+ * Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/atomic.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/interrupt.h>
+#include <linux/hrtimer.h>
+#include <linux/tick.h>
+#include <linux/kfifo.h>
+#include <linux/kgdb.h>
+#include <linux/kdb.h>
+
+static int kgdb_nmi_knock = 1;
+module_param_named(knock, kgdb_nmi_knock, int, 0600);
+MODULE_PARM_DESC(knock, "if set to 1 (default), the special '$3#33' command " \
+ "must be used to enter the debugger; when set to 0, " \
+ "hitting return key is enough to enter the debugger; " \
+ "when set to -1, the debugger is entered immediately " \
+ "upon NMI");
+
+static char *kgdb_nmi_magic = "$3#33";
+module_param_named(magic, kgdb_nmi_magic, charp, 0600);
+MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)");
+
+static bool kgdb_nmi_tty_enabled;
+
+static void kgdb_nmi_console_write(struct console *co, const char *s, uint c)
+{
+ int i;
+
+ if (!kgdb_nmi_tty_enabled || atomic_read(&kgdb_active) >= 0)
+ return;
+
+ for (i = 0; i < c; i++)
+ dbg_io_ops->write_char(s[i]);
+}
+
+static struct tty_driver *kgdb_nmi_tty_driver;
+
+static struct tty_driver *kgdb_nmi_console_device(struct console *co, int *idx)
+{
+ *idx = co->index;
+ return kgdb_nmi_tty_driver;
+}
+
+static struct console kgdb_nmi_console = {
+ .name = "ttyNMI",
+ .write = kgdb_nmi_console_write,
+ .device = kgdb_nmi_console_device,
+ .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED,
+ .index = -1,
+};
+
+/*
+ * This is usually the maximum rate on debug ports. We make fifo large enough
+ * to make copy-pasting to the terminal usable.
+ */
+#define KGDB_NMI_BAUD 115200
+#define KGDB_NMI_FIFO_SIZE roundup_pow_of_two(KGDB_NMI_BAUD / 8 / HZ)
+
+struct kgdb_nmi_tty_priv {
+ struct tty_port port;
+ struct tasklet_struct tlet;
+ STRUCT_KFIFO(char, KGDB_NMI_FIFO_SIZE) fifo;
+};
+
+static struct kgdb_nmi_tty_priv *kgdb_nmi_port_to_priv(struct tty_port *port)
+{
+ return container_of(port, struct kgdb_nmi_tty_priv, port);
+}
+
+/*
+ * Our debugging console is polled in a tasklet, so we'll check for input
+ * every tick. In HZ-less mode, we should program the next tick. We have
+ * to use the lowlevel stuff as no locks should be grabbed.
+ */
+#ifdef CONFIG_HIGH_RES_TIMERS
+static void kgdb_tty_poke(void)
+{
+ tick_program_event(ktime_get(), 0);
+}
+#else
+static inline void kgdb_tty_poke(void) {}
+#endif
+
+static struct tty_port *kgdb_nmi_port;
+
+static void kgdb_tty_recv(int ch)
+{
+ struct kgdb_nmi_tty_priv *priv;
+ char c = ch;
+
+ if (!kgdb_nmi_port || ch < 0)
+ return;
+ /*
+ * Can't use port->tty->driver_data as tty might be not there. Tasklet
+ * will check for tty and will get the ref, but here we don't have to
+ * do that, and actually, we can't: we're in NMI context, no locks are
+ * possible.
+ */
+ priv = kgdb_nmi_port_to_priv(kgdb_nmi_port);
+ kfifo_in(&priv->fifo, &c, 1);
+ kgdb_tty_poke();
+}
+
+static int kgdb_nmi_poll_one_knock(void)
+{
+ static int n;
+ int c = -1;
+ const char *magic = kgdb_nmi_magic;
+ size_t m = strlen(magic);
+ bool printch = 0;
+
+ c = dbg_io_ops->read_char();
+ if (c == NO_POLL_CHAR)
+ return c;
+
+ if (!kgdb_nmi_knock && (c == '\r' || c == '\n')) {
+ return 1;
+ } else if (c == magic[n]) {
+ n = (n + 1) % m;
+ if (!n)
+ return 1;
+ printch = 1;
+ } else {
+ n = 0;
+ }
+
+ if (kgdb_nmi_tty_enabled) {
+ kgdb_tty_recv(c);
+ return 0;
+ }
+
+ if (printch) {
+ kdb_printf("%c", c);
+ return 0;
+ }
+
+ kdb_printf("\r%s %s to enter the debugger> %*s",
+ kgdb_nmi_knock ? "Type" : "Hit",
+ kgdb_nmi_knock ? magic : "<return>", (int)m, "");
+ while (m--)
+ kdb_printf("\b");
+ return 0;
+}
+
+/**
+ * kgdb_nmi_poll_knock - Check if it is time to enter the debugger
+ *
+ * "Serial ports are often noisy, especially when muxed over another port (we
+ * often use serial over the headset connector). Noise on the async command
+ * line just causes characters that are ignored, on a command line that blocked
+ * execution noise would be catastrophic." -- Colin Cross
+ *
+ * So, this function implements KGDB/KDB knocking on the serial line: we won't
+ * enter the debugger until we receive a known magic phrase (which is actually
+ * "$3#33", known as "escape to KDB" command. There is also a relaxed variant
+ * of knocking, i.e. just pressing the return key is enough to enter the
+ * debugger. And if knocking is disabled, the function always returns 1.
+ */
+bool kgdb_nmi_poll_knock(void)
+{
+ if (kgdb_nmi_knock < 0)
+ return 1;
+
+ while (1) {
+ int ret;
+
+ ret = kgdb_nmi_poll_one_knock();
+ if (ret == NO_POLL_CHAR)
+ return 0;
+ else if (ret == 1)
+ break;
+ }
+ return 1;
+}
+
+/*
+ * The tasklet is cheap, it does not cause wakeups when reschedules itself,
+ * instead it waits for the next tick.
+ */
+static void kgdb_nmi_tty_receiver(unsigned long data)
+{
+ struct kgdb_nmi_tty_priv *priv = (void *)data;
+ struct tty_struct *tty;
+ char ch;
+
+ tasklet_schedule(&priv->tlet);
+
+ if (likely(!kgdb_nmi_tty_enabled || !kfifo_len(&priv->fifo)))
+ return;
+
+ /* Port is there, but tty might be hung up, check. */
+ tty = tty_port_tty_get(kgdb_nmi_port);
+ if (!tty)
+ return;
+
+ while (kfifo_out(&priv->fifo, &ch, 1))
+ tty_insert_flip_char(priv->port.tty, ch, TTY_NORMAL);
+ tty_flip_buffer_push(priv->port.tty);
+
+ tty_kref_put(tty);
+}
+
+static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty)
+{
+ struct kgdb_nmi_tty_priv *priv = tty->driver_data;
+
+ kgdb_nmi_port = port;
+ tasklet_schedule(&priv->tlet);
+ return 0;
+}
+
+static void kgdb_nmi_tty_shutdown(struct tty_port *port)
+{
+ struct kgdb_nmi_tty_priv *priv = port->tty->driver_data;
+
+ tasklet_kill(&priv->tlet);
+ kgdb_nmi_port = NULL;
+}
+
+static const struct tty_port_operations kgdb_nmi_tty_port_ops = {
+ .activate = kgdb_nmi_tty_activate,
+ .shutdown = kgdb_nmi_tty_shutdown,
+};
+
+static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty)
+{
+ struct kgdb_nmi_tty_priv *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ INIT_KFIFO(priv->fifo);
+ tasklet_init(&priv->tlet, kgdb_nmi_tty_receiver, (unsigned long)priv);
+ tty_port_init(&priv->port);
+ priv->port.ops = &kgdb_nmi_tty_port_ops;
+ tty->driver_data = priv;
+
+ ret = tty_port_install(&priv->port, drv, tty);
+ if (ret) {
+ pr_err("%s: can't install tty port: %d\n", __func__, ret);
+ goto err;
+ }
+ return 0;
+err:
+ kfree(priv);
+ return ret;
+}
+
+static void kgdb_nmi_tty_cleanup(struct tty_struct *tty)
+{
+ struct kgdb_nmi_tty_priv *priv = tty->driver_data;
+
+ tty->driver_data = NULL;
+ kfree(priv);
+}
+
+static int kgdb_nmi_tty_open(struct tty_struct *tty, struct file *file)
+{
+ struct kgdb_nmi_tty_priv *priv = tty->driver_data;
+
+ return tty_port_open(&priv->port, tty, file);
+}
+
+static void kgdb_nmi_tty_close(struct tty_struct *tty, struct file *file)
+{
+ struct kgdb_nmi_tty_priv *priv = tty->driver_data;
+
+ tty_port_close(&priv->port, tty, file);
+}
+
+static void kgdb_nmi_tty_hangup(struct tty_struct *tty)
+{
+ struct kgdb_nmi_tty_priv *priv = tty->driver_data;
+
+ tty_port_hangup(&priv->port);
+}
+
+static int kgdb_nmi_tty_write_room(struct tty_struct *tty)
+{
+ /* Actually, we can handle any amount as we use polled writes. */
+ return 2048;
+}
+
+static int kgdb_nmi_tty_write(struct tty_struct *tty, const unchar *buf, int c)
+{
+ int i;
+
+ for (i = 0; i < c; i++)
+ dbg_io_ops->write_char(buf[i]);
+ return c;
+}
+
+static const struct tty_operations kgdb_nmi_tty_ops = {
+ .open = kgdb_nmi_tty_open,
+ .close = kgdb_nmi_tty_close,
+ .install = kgdb_nmi_tty_install,
+ .cleanup = kgdb_nmi_tty_cleanup,
+ .hangup = kgdb_nmi_tty_hangup,
+ .write_room = kgdb_nmi_tty_write_room,
+ .write = kgdb_nmi_tty_write,
+};
+
+static int kgdb_nmi_enable_console(int argc, const char *argv[])
+{
+ kgdb_nmi_tty_enabled = !(argc == 1 && !strcmp(argv[1], "off"));
+ return 0;
+}
+
+int kgdb_register_nmi_console(void)
+{
+ int ret;
+
+ if (!arch_kgdb_ops.enable_nmi)
+ return 0;
+
+ kgdb_nmi_tty_driver = alloc_tty_driver(1);
+ if (!kgdb_nmi_tty_driver) {
+ pr_err("%s: cannot allocate tty\n", __func__);
+ return -ENOMEM;
+ }
+ kgdb_nmi_tty_driver->driver_name = "ttyNMI";
+ kgdb_nmi_tty_driver->name = "ttyNMI";
+ kgdb_nmi_tty_driver->num = 1;
+ kgdb_nmi_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ kgdb_nmi_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+ kgdb_nmi_tty_driver->flags = TTY_DRIVER_REAL_RAW;
+ kgdb_nmi_tty_driver->init_termios = tty_std_termios;
+ tty_termios_encode_baud_rate(&kgdb_nmi_tty_driver->init_termios,
+ KGDB_NMI_BAUD, KGDB_NMI_BAUD);
+ tty_set_operations(kgdb_nmi_tty_driver, &kgdb_nmi_tty_ops);
+
+ ret = tty_register_driver(kgdb_nmi_tty_driver);
+ if (ret) {
+ pr_err("%s: can't register tty driver: %d\n", __func__, ret);
+ goto err_drv_reg;
+ }
+
+ ret = kdb_register("nmi_console", kgdb_nmi_enable_console, "[off]",
+ "switch to Linux NMI console", 0);
+ if (ret) {
+ pr_err("%s: can't register kdb command: %d\n", __func__, ret);
+ goto err_kdb_reg;
+ }
+
+ register_console(&kgdb_nmi_console);
+ arch_kgdb_ops.enable_nmi(1);
+
+ return 0;
+err_kdb_reg:
+ tty_unregister_driver(kgdb_nmi_tty_driver);
+err_drv_reg:
+ put_tty_driver(kgdb_nmi_tty_driver);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(kgdb_register_nmi_console);
+
+int kgdb_unregister_nmi_console(void)
+{
+ int ret;
+
+ if (!arch_kgdb_ops.enable_nmi)
+ return 0;
+ arch_kgdb_ops.enable_nmi(0);
+
+ kdb_unregister("nmi_console");
+
+ ret = unregister_console(&kgdb_nmi_console);
+ if (ret)
+ return ret;
+
+ ret = tty_unregister_driver(kgdb_nmi_tty_driver);
+ if (ret)
+ return ret;
+ put_tty_driver(kgdb_nmi_tty_driver);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kgdb_unregister_nmi_console);
diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index 2b42a01a81c6..3f63d834cbc9 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -145,6 +145,8 @@ __setup("kgdboc=", kgdboc_option_setup);
static void cleanup_kgdboc(void)
{
+ if (kgdb_unregister_nmi_console())
+ return;
kgdboc_unregister_kbd();
if (configured == 1)
kgdb_unregister_io_module(&kgdboc_io_ops);
@@ -198,11 +200,18 @@ do_register:
if (err)
goto noconfig;
+ err = kgdb_register_nmi_console();
+ if (err)
+ goto nmi_con_failed;
+
configured = 1;
return 0;
+nmi_con_failed:
+ kgdb_unregister_io_module(&kgdboc_io_ops);
noconfig:
+ kgdboc_unregister_kbd();
config[0] = 0;
configured = 0;
cleanup_kgdboc();
diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c
new file mode 100644
index 000000000000..ba3af3bf6d43
--- /dev/null
+++ b/drivers/tty/serial/lpc32xx_hs.c
@@ -0,0 +1,823 @@
+/*
+ * High Speed Serial Ports on NXP LPC32xx SoC
+ *
+ * Authors: Kevin Wells <kevin.wells@nxp.com>
+ * Roland Stigge <stigge@antcom.de>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/nmi.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <mach/platform.h>
+#include <mach/hardware.h>
+
+/*
+ * High Speed UART register offsets
+ */
+#define LPC32XX_HSUART_FIFO(x) ((x) + 0x00)
+#define LPC32XX_HSUART_LEVEL(x) ((x) + 0x04)
+#define LPC32XX_HSUART_IIR(x) ((x) + 0x08)
+#define LPC32XX_HSUART_CTRL(x) ((x) + 0x0C)
+#define LPC32XX_HSUART_RATE(x) ((x) + 0x10)
+
+#define LPC32XX_HSU_BREAK_DATA (1 << 10)
+#define LPC32XX_HSU_ERROR_DATA (1 << 9)
+#define LPC32XX_HSU_RX_EMPTY (1 << 8)
+
+#define LPC32XX_HSU_TX_LEV(n) (((n) >> 8) & 0xFF)
+#define LPC32XX_HSU_RX_LEV(n) ((n) & 0xFF)
+
+#define LPC32XX_HSU_TX_INT_SET (1 << 6)
+#define LPC32XX_HSU_RX_OE_INT (1 << 5)
+#define LPC32XX_HSU_BRK_INT (1 << 4)
+#define LPC32XX_HSU_FE_INT (1 << 3)
+#define LPC32XX_HSU_RX_TIMEOUT_INT (1 << 2)
+#define LPC32XX_HSU_RX_TRIG_INT (1 << 1)
+#define LPC32XX_HSU_TX_INT (1 << 0)
+
+#define LPC32XX_HSU_HRTS_INV (1 << 21)
+#define LPC32XX_HSU_HRTS_TRIG_8B (0x0 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_16B (0x1 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_32B (0x2 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_48B (0x3 << 19)
+#define LPC32XX_HSU_HRTS_EN (1 << 18)
+#define LPC32XX_HSU_TMO_DISABLED (0x0 << 16)
+#define LPC32XX_HSU_TMO_INACT_4B (0x1 << 16)
+#define LPC32XX_HSU_TMO_INACT_8B (0x2 << 16)
+#define LPC32XX_HSU_TMO_INACT_16B (0x3 << 16)
+#define LPC32XX_HSU_HCTS_INV (1 << 15)
+#define LPC32XX_HSU_HCTS_EN (1 << 14)
+#define LPC32XX_HSU_OFFSET(n) ((n) << 9)
+#define LPC32XX_HSU_BREAK (1 << 8)
+#define LPC32XX_HSU_ERR_INT_EN (1 << 7)
+#define LPC32XX_HSU_RX_INT_EN (1 << 6)
+#define LPC32XX_HSU_TX_INT_EN (1 << 5)
+#define LPC32XX_HSU_RX_TL1B (0x0 << 2)
+#define LPC32XX_HSU_RX_TL4B (0x1 << 2)
+#define LPC32XX_HSU_RX_TL8B (0x2 << 2)
+#define LPC32XX_HSU_RX_TL16B (0x3 << 2)
+#define LPC32XX_HSU_RX_TL32B (0x4 << 2)
+#define LPC32XX_HSU_RX_TL48B (0x5 << 2)
+#define LPC32XX_HSU_TX_TLEMPTY (0x0 << 0)
+#define LPC32XX_HSU_TX_TL0B (0x0 << 0)
+#define LPC32XX_HSU_TX_TL4B (0x1 << 0)
+#define LPC32XX_HSU_TX_TL8B (0x2 << 0)
+#define LPC32XX_HSU_TX_TL16B (0x3 << 0)
+
+#define MODNAME "lpc32xx_hsuart"
+
+struct lpc32xx_hsuart_port {
+ struct uart_port port;
+};
+
+#define FIFO_READ_LIMIT 128
+#define MAX_PORTS 3
+#define LPC32XX_TTY_NAME "ttyTX"
+static struct lpc32xx_hsuart_port lpc32xx_hs_ports[MAX_PORTS];
+
+#ifdef CONFIG_SERIAL_HS_LPC32XX_CONSOLE
+static void wait_for_xmit_empty(struct uart_port *port)
+{
+ unsigned int timeout = 10000;
+
+ do {
+ if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(
+ port->membase))) == 0)
+ break;
+ if (--timeout == 0)
+ break;
+ udelay(1);
+ } while (1);
+}
+
+static void wait_for_xmit_ready(struct uart_port *port)
+{
+ unsigned int timeout = 10000;
+
+ while (1) {
+ if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(
+ port->membase))) < 32)
+ break;
+ if (--timeout == 0)
+ break;
+ udelay(1);
+ }
+}
+
+static void lpc32xx_hsuart_console_putchar(struct uart_port *port, int ch)
+{
+ wait_for_xmit_ready(port);
+ writel((u32)ch, LPC32XX_HSUART_FIFO(port->membase));
+}
+
+static void lpc32xx_hsuart_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct lpc32xx_hsuart_port *up = &lpc32xx_hs_ports[co->index];
+ unsigned long flags;
+ int locked = 1;
+
+ touch_nmi_watchdog();
+ local_irq_save(flags);
+ if (up->port.sysrq)
+ locked = 0;
+ else if (oops_in_progress)
+ locked = spin_trylock(&up->port.lock);
+ else
+ spin_lock(&up->port.lock);
+
+ uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar);
+ wait_for_xmit_empty(&up->port);
+
+ if (locked)
+ spin_unlock(&up->port.lock);
+ local_irq_restore(flags);
+}
+
+static int __init lpc32xx_hsuart_console_setup(struct console *co,
+ char *options)
+{
+ struct uart_port *port;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index >= MAX_PORTS)
+ co->index = 0;
+
+ port = &lpc32xx_hs_ports[co->index].port;
+ if (!port->membase)
+ 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 lpc32xx_hsuart_reg;
+static struct console lpc32xx_hsuart_console = {
+ .name = LPC32XX_TTY_NAME,
+ .write = lpc32xx_hsuart_console_write,
+ .device = uart_console_device,
+ .setup = lpc32xx_hsuart_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &lpc32xx_hsuart_reg,
+};
+
+static int __init lpc32xx_hsuart_console_init(void)
+{
+ register_console(&lpc32xx_hsuart_console);
+ return 0;
+}
+console_initcall(lpc32xx_hsuart_console_init);
+
+#define LPC32XX_HSUART_CONSOLE (&lpc32xx_hsuart_console)
+#else
+#define LPC32XX_HSUART_CONSOLE NULL
+#endif
+
+static struct uart_driver lpc32xx_hs_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = MODNAME,
+ .dev_name = LPC32XX_TTY_NAME,
+ .nr = MAX_PORTS,
+ .cons = LPC32XX_HSUART_CONSOLE,
+};
+static int uarts_registered;
+
+static unsigned int __serial_get_clock_div(unsigned long uartclk,
+ unsigned long rate)
+{
+ u32 div, goodrate, hsu_rate, l_hsu_rate, comprate;
+ u32 rate_diff;
+
+ /* Find the closest divider to get the desired clock rate */
+ div = uartclk / rate;
+ goodrate = hsu_rate = (div / 14) - 1;
+ if (hsu_rate != 0)
+ hsu_rate--;
+
+ /* Tweak divider */
+ l_hsu_rate = hsu_rate + 3;
+ rate_diff = 0xFFFFFFFF;
+
+ while (hsu_rate < l_hsu_rate) {
+ comprate = uartclk / ((hsu_rate + 1) * 14);
+ if (abs(comprate - rate) < rate_diff) {
+ goodrate = hsu_rate;
+ rate_diff = abs(comprate - rate);
+ }
+
+ hsu_rate++;
+ }
+ if (hsu_rate > 0xFF)
+ hsu_rate = 0xFF;
+
+ return goodrate;
+}
+
+static void __serial_uart_flush(struct uart_port *port)
+{
+ u32 tmp;
+ int cnt = 0;
+
+ while ((readl(LPC32XX_HSUART_LEVEL(port->membase)) > 0) &&
+ (cnt++ < FIFO_READ_LIMIT))
+ tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+}
+
+static void __serial_lpc32xx_rx(struct uart_port *port)
+{
+ unsigned int tmp, flag;
+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+
+ if (!tty) {
+ /* Discard data: no tty available */
+ while (!(readl(LPC32XX_HSUART_FIFO(port->membase)) &
+ LPC32XX_HSU_RX_EMPTY))
+ ;
+
+ return;
+ }
+
+ /* Read data from FIFO and push into terminal */
+ tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+ while (!(tmp & LPC32XX_HSU_RX_EMPTY)) {
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (tmp & LPC32XX_HSU_ERROR_DATA) {
+ /* Framing error */
+ writel(LPC32XX_HSU_FE_INT,
+ LPC32XX_HSUART_IIR(port->membase));
+ port->icount.frame++;
+ flag = TTY_FRAME;
+ tty_insert_flip_char(tty, 0, TTY_FRAME);
+ }
+
+ tty_insert_flip_char(tty, (tmp & 0xFF), flag);
+
+ tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+ }
+ tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
+}
+
+static void __serial_lpc32xx_tx(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned int tmp;
+
+ if (port->x_char) {
+ writel((u32)port->x_char, LPC32XX_HSUART_FIFO(port->membase));
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+ goto exit_tx;
+
+ /* Transfer data */
+ while (LPC32XX_HSU_TX_LEV(readl(
+ LPC32XX_HSUART_LEVEL(port->membase))) < 64) {
+ writel((u32) xmit->buf[xmit->tail],
+ LPC32XX_HSUART_FIFO(port->membase));
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+exit_tx:
+ if (uart_circ_empty(xmit)) {
+ tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+ tmp &= ~LPC32XX_HSU_TX_INT_EN;
+ writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+ }
+}
+
+static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+ u32 status;
+
+ spin_lock(&port->lock);
+
+ /* Read UART status and clear latched interrupts */
+ status = readl(LPC32XX_HSUART_IIR(port->membase));
+
+ if (status & LPC32XX_HSU_BRK_INT) {
+ /* Break received */
+ writel(LPC32XX_HSU_BRK_INT, LPC32XX_HSUART_IIR(port->membase));
+ port->icount.brk++;
+ uart_handle_break(port);
+ }
+
+ /* Framing error */
+ if (status & LPC32XX_HSU_FE_INT)
+ writel(LPC32XX_HSU_FE_INT, LPC32XX_HSUART_IIR(port->membase));
+
+ if (status & LPC32XX_HSU_RX_OE_INT) {
+ /* Receive FIFO overrun */
+ writel(LPC32XX_HSU_RX_OE_INT,
+ LPC32XX_HSUART_IIR(port->membase));
+ port->icount.overrun++;
+ if (tty) {
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ tty_schedule_flip(tty);
+ }
+ }
+
+ /* Data received? */
+ if (status & (LPC32XX_HSU_RX_TIMEOUT_INT | LPC32XX_HSU_RX_TRIG_INT)) {
+ __serial_lpc32xx_rx(port);
+ if (tty)
+ tty_flip_buffer_push(tty);
+ }
+
+ /* Transmit data request? */
+ if ((status & LPC32XX_HSU_TX_INT) && (!uart_tx_stopped(port))) {
+ writel(LPC32XX_HSU_TX_INT, LPC32XX_HSUART_IIR(port->membase));
+ __serial_lpc32xx_tx(port);
+ }
+
+ spin_unlock(&port->lock);
+ tty_kref_put(tty);
+
+ return IRQ_HANDLED;
+}
+
+/* port->lock is not held. */
+static unsigned int serial_lpc32xx_tx_empty(struct uart_port *port)
+{
+ unsigned int ret = 0;
+
+ if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(port->membase))) == 0)
+ ret = TIOCSER_TEMT;
+
+ return ret;
+}
+
+/* port->lock held by caller. */
+static void serial_lpc32xx_set_mctrl(struct uart_port *port,
+ unsigned int mctrl)
+{
+ /* No signals are supported on HS UARTs */
+}
+
+/* port->lock is held by caller and interrupts are disabled. */
+static unsigned int serial_lpc32xx_get_mctrl(struct uart_port *port)
+{
+ /* No signals are supported on HS UARTs */
+ return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/* port->lock held by caller. */
+static void serial_lpc32xx_stop_tx(struct uart_port *port)
+{
+ u32 tmp;
+
+ tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+ tmp &= ~LPC32XX_HSU_TX_INT_EN;
+ writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+}
+
+/* port->lock held by caller. */
+static void serial_lpc32xx_start_tx(struct uart_port *port)
+{
+ u32 tmp;
+
+ __serial_lpc32xx_tx(port);
+ tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+ tmp |= LPC32XX_HSU_TX_INT_EN;
+ writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+}
+
+/* port->lock held by caller. */
+static void serial_lpc32xx_stop_rx(struct uart_port *port)
+{
+ u32 tmp;
+
+ tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+ tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN);
+ writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+ writel((LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT |
+ LPC32XX_HSU_FE_INT), LPC32XX_HSUART_IIR(port->membase));
+}
+
+/* port->lock held by caller. */
+static void serial_lpc32xx_enable_ms(struct uart_port *port)
+{
+ /* Modem status is not supported */
+}
+
+/* port->lock is not held. */
+static void serial_lpc32xx_break_ctl(struct uart_port *port,
+ int break_state)
+{
+ unsigned long flags;
+ u32 tmp;
+
+ spin_lock_irqsave(&port->lock, flags);
+ tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+ if (break_state != 0)
+ tmp |= LPC32XX_HSU_BREAK;
+ else
+ tmp &= ~LPC32XX_HSU_BREAK;
+ writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* LPC3250 Errata HSUART.1: Hang workaround via loopback mode on inactivity */
+static void lpc32xx_loopback_set(resource_size_t mapbase, int state)
+{
+ int bit;
+ u32 tmp;
+
+ switch (mapbase) {
+ case LPC32XX_HS_UART1_BASE:
+ bit = 0;
+ break;
+ case LPC32XX_HS_UART2_BASE:
+ bit = 1;
+ break;
+ case LPC32XX_HS_UART7_BASE:
+ bit = 6;
+ break;
+ default:
+ WARN(1, "lpc32xx_hs: Warning: Unknown port at %08x\n", mapbase);
+ return;
+ }
+
+ tmp = readl(LPC32XX_UARTCTL_CLOOP);
+ if (state)
+ tmp |= (1 << bit);
+ else
+ tmp &= ~(1 << bit);
+ writel(tmp, LPC32XX_UARTCTL_CLOOP);
+}
+
+/* port->lock is not held. */
+static int serial_lpc32xx_startup(struct uart_port *port)
+{
+ int retval;
+ unsigned long flags;
+ u32 tmp;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ __serial_uart_flush(port);
+
+ writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT |
+ LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT),
+ LPC32XX_HSUART_IIR(port->membase));
+
+ writel(0xFF, LPC32XX_HSUART_RATE(port->membase));
+
+ /*
+ * Set receiver timeout, HSU offset of 20, no break, no interrupts,
+ * and default FIFO trigger levels
+ */
+ tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+ LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B;
+ writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+ lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ retval = request_irq(port->irq, serial_lpc32xx_interrupt,
+ 0, MODNAME, port);
+ if (!retval)
+ writel((tmp | LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN),
+ LPC32XX_HSUART_CTRL(port->membase));
+
+ return retval;
+}
+
+/* port->lock is not held. */
+static void serial_lpc32xx_shutdown(struct uart_port *port)
+{
+ u32 tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+ LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B;
+ writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+ lpc32xx_loopback_set(port->mapbase, 1); /* go to loopback mode */
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ free_irq(port->irq, port);
+}
+
+/* port->lock is not held. */
+static void serial_lpc32xx_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned long flags;
+ unsigned int baud, quot;
+ u32 tmp;
+
+ /* Always 8-bit, no parity, 1 stop bit */
+ termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
+ termios->c_cflag |= CS8;
+
+ termios->c_cflag &= ~(HUPCL | CMSPAR | CLOCAL | CRTSCTS);
+
+ baud = uart_get_baud_rate(port, termios, old, 0,
+ port->uartclk / 14);
+
+ quot = __serial_get_clock_div(port->uartclk, baud);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* Ignore characters? */
+ tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+ if ((termios->c_cflag & CREAD) == 0)
+ tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN);
+ else
+ tmp |= LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN;
+ writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+ writel(quot, LPC32XX_HSUART_RATE(port->membase));
+
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ /* Don't rewrite B0 */
+ if (tty_termios_baud_rate(termios))
+ tty_termios_encode_baud_rate(termios, baud, baud);
+}
+
+static const char *serial_lpc32xx_type(struct uart_port *port)
+{
+ return MODNAME;
+}
+
+static void serial_lpc32xx_release_port(struct uart_port *port)
+{
+ if ((port->iotype == UPIO_MEM32) && (port->mapbase)) {
+ if (port->flags & UPF_IOREMAP) {
+ iounmap(port->membase);
+ port->membase = NULL;
+ }
+
+ release_mem_region(port->mapbase, SZ_4K);
+ }
+}
+
+static int serial_lpc32xx_request_port(struct uart_port *port)
+{
+ int ret = -ENODEV;
+
+ if ((port->iotype == UPIO_MEM32) && (port->mapbase)) {
+ ret = 0;
+
+ if (!request_mem_region(port->mapbase, SZ_4K, MODNAME))
+ ret = -EBUSY;
+ else if (port->flags & UPF_IOREMAP) {
+ port->membase = ioremap(port->mapbase, SZ_4K);
+ if (!port->membase) {
+ release_mem_region(port->mapbase, SZ_4K);
+ ret = -ENOMEM;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static void serial_lpc32xx_config_port(struct uart_port *port, int uflags)
+{
+ int ret;
+
+ ret = serial_lpc32xx_request_port(port);
+ if (ret < 0)
+ return;
+ port->type = PORT_UART00;
+ port->fifosize = 64;
+
+ __serial_uart_flush(port);
+
+ writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT |
+ LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT),
+ LPC32XX_HSUART_IIR(port->membase));
+
+ writel(0xFF, LPC32XX_HSUART_RATE(port->membase));
+
+ /* Set receiver timeout, HSU offset of 20, no break, no interrupts,
+ and default FIFO trigger levels */
+ writel(LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+ LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B,
+ LPC32XX_HSUART_CTRL(port->membase));
+}
+
+static int serial_lpc32xx_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+{
+ int ret = 0;
+
+ if (ser->type != PORT_UART00)
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static struct uart_ops serial_lpc32xx_pops = {
+ .tx_empty = serial_lpc32xx_tx_empty,
+ .set_mctrl = serial_lpc32xx_set_mctrl,
+ .get_mctrl = serial_lpc32xx_get_mctrl,
+ .stop_tx = serial_lpc32xx_stop_tx,
+ .start_tx = serial_lpc32xx_start_tx,
+ .stop_rx = serial_lpc32xx_stop_rx,
+ .enable_ms = serial_lpc32xx_enable_ms,
+ .break_ctl = serial_lpc32xx_break_ctl,
+ .startup = serial_lpc32xx_startup,
+ .shutdown = serial_lpc32xx_shutdown,
+ .set_termios = serial_lpc32xx_set_termios,
+ .type = serial_lpc32xx_type,
+ .release_port = serial_lpc32xx_release_port,
+ .request_port = serial_lpc32xx_request_port,
+ .config_port = serial_lpc32xx_config_port,
+ .verify_port = serial_lpc32xx_verify_port,
+};
+
+/*
+ * Register a set of serial devices attached to a platform device
+ */
+static int __devinit serial_hs_lpc32xx_probe(struct platform_device *pdev)
+{
+ struct lpc32xx_hsuart_port *p = &lpc32xx_hs_ports[uarts_registered];
+ int ret = 0;
+ struct resource *res;
+
+ if (uarts_registered >= MAX_PORTS) {
+ dev_err(&pdev->dev,
+ "Error: Number of possible ports exceeded (%d)!\n",
+ uarts_registered + 1);
+ return -ENXIO;
+ }
+
+ memset(p, 0, sizeof(*p));
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Error getting mem resource for HS UART port %d\n",
+ uarts_registered);
+ return -ENXIO;
+ }
+ p->port.mapbase = res->start;
+ p->port.membase = NULL;
+
+ p->port.irq = platform_get_irq(pdev, 0);
+ if (p->port.irq < 0) {
+ dev_err(&pdev->dev, "Error getting irq for HS UART port %d\n",
+ uarts_registered);
+ return p->port.irq;
+ }
+
+ p->port.iotype = UPIO_MEM32;
+ p->port.uartclk = LPC32XX_MAIN_OSC_FREQ;
+ p->port.regshift = 2;
+ p->port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
+ p->port.dev = &pdev->dev;
+ p->port.ops = &serial_lpc32xx_pops;
+ p->port.line = uarts_registered++;
+ spin_lock_init(&p->port.lock);
+
+ /* send port to loopback mode by default */
+ lpc32xx_loopback_set(p->port.mapbase, 1);
+
+ ret = uart_add_one_port(&lpc32xx_hs_reg, &p->port);
+
+ platform_set_drvdata(pdev, p);
+
+ return ret;
+}
+
+/*
+ * Remove serial ports registered against a platform device.
+ */
+static int __devexit serial_hs_lpc32xx_remove(struct platform_device *pdev)
+{
+ struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+ uart_remove_one_port(&lpc32xx_hs_reg, &p->port);
+
+ return 0;
+}
+
+
+#ifdef CONFIG_PM
+static int serial_hs_lpc32xx_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+ uart_suspend_port(&lpc32xx_hs_reg, &p->port);
+
+ return 0;
+}
+
+static int serial_hs_lpc32xx_resume(struct platform_device *pdev)
+{
+ struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+ uart_resume_port(&lpc32xx_hs_reg, &p->port);
+
+ return 0;
+}
+#else
+#define serial_hs_lpc32xx_suspend NULL
+#define serial_hs_lpc32xx_resume NULL
+#endif
+
+static const struct of_device_id serial_hs_lpc32xx_dt_ids[] = {
+ { .compatible = "nxp,lpc3220-hsuart" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, serial_hs_lpc32xx_dt_ids);
+
+static struct platform_driver serial_hs_lpc32xx_driver = {
+ .probe = serial_hs_lpc32xx_probe,
+ .remove = __devexit_p(serial_hs_lpc32xx_remove),
+ .suspend = serial_hs_lpc32xx_suspend,
+ .resume = serial_hs_lpc32xx_resume,
+ .driver = {
+ .name = MODNAME,
+ .owner = THIS_MODULE,
+ .of_match_table = serial_hs_lpc32xx_dt_ids,
+ },
+};
+
+static int __init lpc32xx_hsuart_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&lpc32xx_hs_reg);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&serial_hs_lpc32xx_driver);
+ if (ret)
+ uart_unregister_driver(&lpc32xx_hs_reg);
+
+ return ret;
+}
+
+static void __exit lpc32xx_hsuart_exit(void)
+{
+ platform_driver_unregister(&serial_hs_lpc32xx_driver);
+ uart_unregister_driver(&lpc32xx_hs_reg);
+}
+
+module_init(lpc32xx_hsuart_init);
+module_exit(lpc32xx_hsuart_exit);
+
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NXP LPC32XX High Speed UART driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c
index a0703624d5e5..b13949ad3408 100644
--- a/drivers/tty/serial/m32r_sio.c
+++ b/drivers/tty/serial/m32r_sio.c
@@ -44,8 +44,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-#define PORT_M32R_BASE PORT_M32R_SIO
-#define PORT_INDEX(x) (x - PORT_M32R_BASE + 1)
#define BAUD_RATE 115200
#include <linux/serial_core.h>
@@ -132,22 +130,6 @@ struct irq_info {
static struct irq_info irq_lists[NR_IRQS];
-/*
- * Here we define the default xmit fifo size used for each type of UART.
- */
-static const struct serial_uart_config uart_config[] = {
- [PORT_UNKNOWN] = {
- .name = "unknown",
- .dfl_xmit_fifo_size = 1,
- .flags = 0,
- },
- [PORT_INDEX(PORT_M32R_SIO)] = {
- .name = "M32RSIO",
- .dfl_xmit_fifo_size = 1,
- .flags = 0,
- },
-};
-
#ifdef CONFIG_SERIAL_M32R_PLDSIO
#define __sio_in(x) inw((unsigned long)(x))
@@ -907,8 +889,7 @@ static void m32r_sio_config_port(struct uart_port *port, int unused)
spin_lock_irqsave(&up->port.lock, flags);
- up->port.type = (PORT_M32R_SIO - PORT_M32R_BASE + 1);
- up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
+ up->port.fifosize = 1;
spin_unlock_irqrestore(&up->port.lock, flags);
}
@@ -916,23 +897,11 @@ static void m32r_sio_config_port(struct uart_port *port, int unused)
static int
m32r_sio_verify_port(struct uart_port *port, struct serial_struct *ser)
{
- if (ser->irq >= nr_irqs || ser->irq < 0 ||
- ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
- ser->type >= ARRAY_SIZE(uart_config))
+ if (ser->irq >= nr_irqs || ser->irq < 0 || ser->baud_base < 9600)
return -EINVAL;
return 0;
}
-static const char *
-m32r_sio_type(struct uart_port *port)
-{
- int type = port->type;
-
- if (type >= ARRAY_SIZE(uart_config))
- type = 0;
- return uart_config[type].name;
-}
-
static struct uart_ops m32r_sio_pops = {
.tx_empty = m32r_sio_tx_empty,
.set_mctrl = m32r_sio_set_mctrl,
@@ -946,7 +915,6 @@ static struct uart_ops m32r_sio_pops = {
.shutdown = m32r_sio_shutdown,
.set_termios = m32r_sio_set_termios,
.pm = m32r_sio_pm,
- .type = m32r_sio_type,
.release_port = m32r_sio_release_port,
.request_port = m32r_sio_request_port,
.config_port = m32r_sio_config_port,
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index b4902b99cfd2..0f24486be532 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -827,14 +827,16 @@ static int __devexit max3100_remove(struct spi_device *spi)
/* find out the index for the chip we are removing */
for (i = 0; i < MAX_MAX3100; i++)
- if (max3100s[i] == s)
+ if (max3100s[i] == s) {
+ dev_dbg(&spi->dev, "%s: removing port %d\n", __func__, i);
+ uart_remove_one_port(&max3100_uart_driver, &max3100s[i]->port);
+ kfree(max3100s[i]);
+ max3100s[i] = NULL;
break;
+ }
- dev_dbg(&spi->dev, "%s: removing port %d\n", __func__, i);
- uart_remove_one_port(&max3100_uart_driver, &max3100s[i]->port);
- kfree(max3100s[i]);
- max3100s[i] = NULL;
-
+ WARN_ON(i == MAX_MAX3100);
+
/* check if this is the last chip we have */
for (i = 0; i < MAX_MAX3100; i++)
if (max3100s[i]) {
@@ -910,17 +912,7 @@ static struct spi_driver max3100_driver = {
.resume = max3100_resume,
};
-static int __init max3100_init(void)
-{
- return spi_register_driver(&max3100_driver);
-}
-module_init(max3100_init);
-
-static void __exit max3100_exit(void)
-{
- spi_unregister_driver(&max3100_driver);
-}
-module_exit(max3100_exit);
+module_spi_driver(max3100_driver);
MODULE_DESCRIPTION("MAX3100 driver");
MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>");
diff --git a/drivers/tty/serial/max3107.c b/drivers/tty/serial/max3107.c
deleted file mode 100644
index 17c7ba805d98..000000000000
--- a/drivers/tty/serial/max3107.c
+++ /dev/null
@@ -1,1215 +0,0 @@
-/*
- * max3107.c - spi uart protocol driver for Maxim 3107
- * Based on max3100.c
- * by Christian Pellegrin <chripell@evolware.org>
- * and max3110.c
- * by Feng Tang <feng.tang@intel.com>
- *
- * Copyright (C) Aavamobile 2009
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * 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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- */
-
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/freezer.h>
-#include <linux/module.h>
-#include "max3107.h"
-
-static const struct baud_table brg26_ext[] = {
- { 300, MAX3107_BRG26_B300 },
- { 600, MAX3107_BRG26_B600 },
- { 1200, MAX3107_BRG26_B1200 },
- { 2400, MAX3107_BRG26_B2400 },
- { 4800, MAX3107_BRG26_B4800 },
- { 9600, MAX3107_BRG26_B9600 },
- { 19200, MAX3107_BRG26_B19200 },
- { 57600, MAX3107_BRG26_B57600 },
- { 115200, MAX3107_BRG26_B115200 },
- { 230400, MAX3107_BRG26_B230400 },
- { 460800, MAX3107_BRG26_B460800 },
- { 921600, MAX3107_BRG26_B921600 },
- { 0, 0 }
-};
-
-static const struct baud_table brg13_int[] = {
- { 300, MAX3107_BRG13_IB300 },
- { 600, MAX3107_BRG13_IB600 },
- { 1200, MAX3107_BRG13_IB1200 },
- { 2400, MAX3107_BRG13_IB2400 },
- { 4800, MAX3107_BRG13_IB4800 },
- { 9600, MAX3107_BRG13_IB9600 },
- { 19200, MAX3107_BRG13_IB19200 },
- { 57600, MAX3107_BRG13_IB57600 },
- { 115200, MAX3107_BRG13_IB115200 },
- { 230400, MAX3107_BRG13_IB230400 },
- { 460800, MAX3107_BRG13_IB460800 },
- { 921600, MAX3107_BRG13_IB921600 },
- { 0, 0 }
-};
-
-static u32 get_new_brg(int baud, struct max3107_port *s)
-{
- int i;
- const struct baud_table *baud_tbl = s->baud_tbl;
-
- for (i = 0; i < 13; i++) {
- if (baud == baud_tbl[i].baud)
- return baud_tbl[i].new_brg;
- }
-
- return 0;
-}
-
-/* Perform SPI transfer for write/read of device register(s) */
-int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len)
-{
- struct spi_message spi_msg;
- struct spi_transfer spi_xfer;
-
- /* Initialize SPI ,message */
- spi_message_init(&spi_msg);
-
- /* Initialize SPI transfer */
- memset(&spi_xfer, 0, sizeof spi_xfer);
- spi_xfer.len = len;
- spi_xfer.tx_buf = tx;
- spi_xfer.rx_buf = rx;
- spi_xfer.speed_hz = MAX3107_SPI_SPEED;
-
- /* Add SPI transfer to SPI message */
- spi_message_add_tail(&spi_xfer, &spi_msg);
-
-#ifdef DBG_TRACE_SPI_DATA
- {
- int i;
- pr_info("tx len %d:\n", spi_xfer.len);
- for (i = 0 ; i < spi_xfer.len && i < 32 ; i++)
- pr_info(" %x", ((u8 *)spi_xfer.tx_buf)[i]);
- pr_info("\n");
- }
-#endif
-
- /* Perform synchronous SPI transfer */
- if (spi_sync(s->spi, &spi_msg)) {
- dev_err(&s->spi->dev, "spi_sync failure\n");
- return -EIO;
- }
-
-#ifdef DBG_TRACE_SPI_DATA
- if (spi_xfer.rx_buf) {
- int i;
- pr_info("rx len %d:\n", spi_xfer.len);
- for (i = 0 ; i < spi_xfer.len && i < 32 ; i++)
- pr_info(" %x", ((u8 *)spi_xfer.rx_buf)[i]);
- pr_info("\n");
- }
-#endif
- return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_rw);
-
-/* Puts received data to circular buffer */
-static void put_data_to_circ_buf(struct max3107_port *s, unsigned char *data,
- int len)
-{
- struct uart_port *port = &s->port;
- struct tty_struct *tty;
-
- if (!port->state)
- return;
-
- tty = port->state->port.tty;
- if (!tty)
- return;
-
- /* Insert received data */
- tty_insert_flip_string(tty, data, len);
- /* Update RX counter */
- port->icount.rx += len;
-}
-
-/* Handle data receiving */
-static void max3107_handlerx(struct max3107_port *s, u16 rxlvl)
-{
- int i;
- int j;
- int len; /* SPI transfer buffer length */
- u16 *buf;
- u8 *valid_str;
-
- if (!s->rx_enabled)
- /* RX is disabled */
- return;
-
- if (rxlvl == 0) {
- /* RX fifo is empty */
- return;
- } else if (rxlvl >= MAX3107_RX_FIFO_SIZE) {
- dev_warn(&s->spi->dev, "Possible RX FIFO overrun %d\n", rxlvl);
- /* Ensure sanity of RX level */
- rxlvl = MAX3107_RX_FIFO_SIZE;
- }
- if ((s->rxbuf == 0) || (s->rxstr == 0)) {
- dev_warn(&s->spi->dev, "Rx buffer/str isn't ready\n");
- return;
- }
- buf = s->rxbuf;
- valid_str = s->rxstr;
- while (rxlvl) {
- pr_debug("rxlvl %d\n", rxlvl);
- /* Clear buffer */
- memset(buf, 0, sizeof(u16) * (MAX3107_RX_FIFO_SIZE + 2));
- len = 0;
- if (s->irqen_reg & MAX3107_IRQ_RXFIFO_BIT) {
- /* First disable RX FIFO interrupt */
- pr_debug("Disabling RX INT\n");
- buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
- s->irqen_reg &= ~MAX3107_IRQ_RXFIFO_BIT;
- buf[0] |= s->irqen_reg;
- len++;
- }
- /* Just increase the length by amount of words in FIFO since
- * buffer was zeroed and SPI transfer of 0x0000 means reading
- * from RX FIFO
- */
- len += rxlvl;
- /* Append RX level query */
- buf[len] = MAX3107_RXFIFOLVL_REG;
- len++;
-
- /* Perform the SPI transfer */
- if (max3107_rw(s, (u8 *)buf, (u8 *)buf, len * 2)) {
- dev_err(&s->spi->dev, "SPI transfer for RX h failed\n");
- return;
- }
-
- /* Skip RX FIFO interrupt disabling word if it was added */
- j = ((len - 1) - rxlvl);
- /* Read received words */
- for (i = 0; i < rxlvl; i++, j++)
- valid_str[i] = (u8)buf[j];
- put_data_to_circ_buf(s, valid_str, rxlvl);
- /* Get new RX level */
- rxlvl = (buf[len - 1] & MAX3107_SPI_RX_DATA_MASK);
- }
-
- if (s->rx_enabled) {
- /* RX still enabled, re-enable RX FIFO interrupt */
- pr_debug("Enabling RX INT\n");
- buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
- s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT;
- buf[0] |= s->irqen_reg;
- if (max3107_rw(s, (u8 *)buf, NULL, 2))
- dev_err(&s->spi->dev, "RX FIFO INT enabling failed\n");
- }
-
- /* Push the received data to receivers */
- if (s->port.state->port.tty)
- tty_flip_buffer_push(s->port.state->port.tty);
-}
-
-
-/* Handle data sending */
-static void max3107_handletx(struct max3107_port *s)
-{
- struct circ_buf *xmit = &s->port.state->xmit;
- int i;
- unsigned long flags;
- int len; /* SPI transfer buffer length */
- u16 *buf;
-
- if (!s->tx_fifo_empty)
- /* Don't send more data before previous data is sent */
- return;
-
- if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port))
- /* No data to send or TX is stopped */
- return;
-
- if (!s->txbuf) {
- dev_warn(&s->spi->dev, "Txbuf isn't ready\n");
- return;
- }
- buf = s->txbuf;
- /* Get length of data pending in circular buffer */
- len = uart_circ_chars_pending(xmit);
- if (len) {
- /* Limit to size of TX FIFO */
- if (len > MAX3107_TX_FIFO_SIZE)
- len = MAX3107_TX_FIFO_SIZE;
-
- pr_debug("txlen %d\n", len);
-
- /* Update TX counter */
- s->port.icount.tx += len;
-
- /* TX FIFO will no longer be empty */
- s->tx_fifo_empty = 0;
-
- i = 0;
- if (s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT) {
- /* First disable TX empty interrupt */
- pr_debug("Disabling TE INT\n");
- buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
- s->irqen_reg &= ~MAX3107_IRQ_TXEMPTY_BIT;
- buf[i] |= s->irqen_reg;
- i++;
- len++;
- }
- /* Add data to send */
- spin_lock_irqsave(&s->port.lock, flags);
- for ( ; i < len ; i++) {
- buf[i] = (MAX3107_WRITE_BIT | MAX3107_THR_REG);
- buf[i] |= ((u16)xmit->buf[xmit->tail] &
- MAX3107_SPI_TX_DATA_MASK);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- }
- spin_unlock_irqrestore(&s->port.lock, flags);
- if (!(s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT)) {
- /* Enable TX empty interrupt */
- pr_debug("Enabling TE INT\n");
- buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
- s->irqen_reg |= MAX3107_IRQ_TXEMPTY_BIT;
- buf[i] |= s->irqen_reg;
- i++;
- len++;
- }
- if (!s->tx_enabled) {
- /* Enable TX */
- pr_debug("Enable TX\n");
- buf[i] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
- spin_lock_irqsave(&s->data_lock, flags);
- s->mode1_reg &= ~MAX3107_MODE1_TXDIS_BIT;
- buf[i] |= s->mode1_reg;
- spin_unlock_irqrestore(&s->data_lock, flags);
- s->tx_enabled = 1;
- i++;
- len++;
- }
-
- /* Perform the SPI transfer */
- if (max3107_rw(s, (u8 *)buf, NULL, len*2)) {
- dev_err(&s->spi->dev,
- "SPI transfer TX handling failed\n");
- return;
- }
- }
-
- /* Indicate wake up if circular buffer is getting low on data */
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&s->port);
-
-}
-
-/* Handle interrupts
- * Also reads and returns current RX FIFO level
- */
-static u16 handle_interrupt(struct max3107_port *s)
-{
- u16 buf[4]; /* Buffer for SPI transfers */
- u8 irq_status;
- u16 rx_level;
- unsigned long flags;
-
- /* Read IRQ status register */
- buf[0] = MAX3107_IRQSTS_REG;
- /* Read status IRQ status register */
- buf[1] = MAX3107_STS_IRQSTS_REG;
- /* Read LSR IRQ status register */
- buf[2] = MAX3107_LSR_IRQSTS_REG;
- /* Query RX level */
- buf[3] = MAX3107_RXFIFOLVL_REG;
-
- if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 8)) {
- dev_err(&s->spi->dev,
- "SPI transfer for INTR handling failed\n");
- return 0;
- }
-
- irq_status = (u8)buf[0];
- pr_debug("IRQSTS %x\n", irq_status);
- rx_level = (buf[3] & MAX3107_SPI_RX_DATA_MASK);
-
- if (irq_status & MAX3107_IRQ_LSR_BIT) {
- /* LSR interrupt */
- if (buf[2] & MAX3107_LSR_RXTO_BIT)
- /* RX timeout interrupt,
- * handled by normal RX handling
- */
- pr_debug("RX TO INT\n");
- }
-
- if (irq_status & MAX3107_IRQ_TXEMPTY_BIT) {
- /* Tx empty interrupt,
- * disable TX and set tx_fifo_empty flag
- */
- pr_debug("TE INT, disabling TX\n");
- buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
- spin_lock_irqsave(&s->data_lock, flags);
- s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT;
- buf[0] |= s->mode1_reg;
- spin_unlock_irqrestore(&s->data_lock, flags);
- if (max3107_rw(s, (u8 *)buf, NULL, 2))
- dev_err(&s->spi->dev, "SPI transfer TX dis failed\n");
- s->tx_enabled = 0;
- s->tx_fifo_empty = 1;
- }
-
- if (irq_status & MAX3107_IRQ_RXFIFO_BIT)
- /* RX FIFO interrupt,
- * handled by normal RX handling
- */
- pr_debug("RFIFO INT\n");
-
- /* Return RX level */
- return rx_level;
-}
-
-/* Trigger work thread*/
-static void max3107_dowork(struct max3107_port *s)
-{
- if (!work_pending(&s->work) && !freezing(current) && !s->suspended)
- queue_work(s->workqueue, &s->work);
- else
- dev_warn(&s->spi->dev, "interrup isn't serviced normally!\n");
-}
-
-/* Work thread */
-static void max3107_work(struct work_struct *w)
-{
- struct max3107_port *s = container_of(w, struct max3107_port, work);
- u16 rxlvl = 0;
- int len; /* SPI transfer buffer length */
- u16 buf[5]; /* Buffer for SPI transfers */
- unsigned long flags;
-
- /* Start by reading current RX FIFO level */
- buf[0] = MAX3107_RXFIFOLVL_REG;
- if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
- dev_err(&s->spi->dev, "SPI transfer RX lev failed\n");
- rxlvl = 0;
- } else {
- rxlvl = (buf[0] & MAX3107_SPI_RX_DATA_MASK);
- }
-
- do {
- pr_debug("rxlvl %d\n", rxlvl);
-
- /* Handle RX */
- max3107_handlerx(s, rxlvl);
- rxlvl = 0;
-
- if (s->handle_irq) {
- /* Handle pending interrupts
- * We also get new RX FIFO level since new data may
- * have been received while pushing received data to
- * receivers
- */
- s->handle_irq = 0;
- rxlvl = handle_interrupt(s);
- }
-
- /* Handle TX */
- max3107_handletx(s);
-
- /* Handle configuration changes */
- len = 0;
- spin_lock_irqsave(&s->data_lock, flags);
- if (s->mode1_commit) {
- pr_debug("mode1_commit\n");
- buf[len] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
- buf[len++] |= s->mode1_reg;
- s->mode1_commit = 0;
- }
- if (s->lcr_commit) {
- pr_debug("lcr_commit\n");
- buf[len] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG);
- buf[len++] |= s->lcr_reg;
- s->lcr_commit = 0;
- }
- if (s->brg_commit) {
- pr_debug("brg_commit\n");
- buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG);
- buf[len++] |= ((s->brg_cfg >> 16) &
- MAX3107_SPI_TX_DATA_MASK);
- buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG);
- buf[len++] |= ((s->brg_cfg >> 8) &
- MAX3107_SPI_TX_DATA_MASK);
- buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG);
- buf[len++] |= ((s->brg_cfg) & 0xff);
- s->brg_commit = 0;
- }
- spin_unlock_irqrestore(&s->data_lock, flags);
-
- if (len > 0) {
- if (max3107_rw(s, (u8 *)buf, NULL, len * 2))
- dev_err(&s->spi->dev,
- "SPI transfer config failed\n");
- }
-
- /* Reloop if interrupt handling indicated data in RX FIFO */
- } while (rxlvl);
-
-}
-
-/* Set sleep mode */
-static void max3107_set_sleep(struct max3107_port *s, int mode)
-{
- u16 buf[1]; /* Buffer for SPI transfer */
- unsigned long flags;
- pr_debug("enter, mode %d\n", mode);
-
- buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
- spin_lock_irqsave(&s->data_lock, flags);
- switch (mode) {
- case MAX3107_DISABLE_FORCED_SLEEP:
- s->mode1_reg &= ~MAX3107_MODE1_FORCESLEEP_BIT;
- break;
- case MAX3107_ENABLE_FORCED_SLEEP:
- s->mode1_reg |= MAX3107_MODE1_FORCESLEEP_BIT;
- break;
- case MAX3107_DISABLE_AUTOSLEEP:
- s->mode1_reg &= ~MAX3107_MODE1_AUTOSLEEP_BIT;
- break;
- case MAX3107_ENABLE_AUTOSLEEP:
- s->mode1_reg |= MAX3107_MODE1_AUTOSLEEP_BIT;
- break;
- default:
- spin_unlock_irqrestore(&s->data_lock, flags);
- dev_warn(&s->spi->dev, "invalid sleep mode\n");
- return;
- }
- buf[0] |= s->mode1_reg;
- spin_unlock_irqrestore(&s->data_lock, flags);
-
- if (max3107_rw(s, (u8 *)buf, NULL, 2))
- dev_err(&s->spi->dev, "SPI transfer sleep mode failed\n");
-
- if (mode == MAX3107_DISABLE_AUTOSLEEP ||
- mode == MAX3107_DISABLE_FORCED_SLEEP)
- msleep(MAX3107_WAKEUP_DELAY);
-}
-
-/* Perform full register initialization */
-static void max3107_register_init(struct max3107_port *s)
-{
- u16 buf[11]; /* Buffer for SPI transfers */
-
- /* 1. Configure baud rate, 9600 as default */
- s->baud = 9600;
- /* the below is default*/
- if (s->ext_clk) {
- s->brg_cfg = MAX3107_BRG26_B9600;
- s->baud_tbl = (struct baud_table *)brg26_ext;
- } else {
- s->brg_cfg = MAX3107_BRG13_IB9600;
- s->baud_tbl = (struct baud_table *)brg13_int;
- }
-
- if (s->pdata->init)
- s->pdata->init(s);
-
- buf[0] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG)
- | ((s->brg_cfg >> 16) & MAX3107_SPI_TX_DATA_MASK);
- buf[1] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG)
- | ((s->brg_cfg >> 8) & MAX3107_SPI_TX_DATA_MASK);
- buf[2] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG)
- | ((s->brg_cfg) & 0xff);
-
- /* 2. Configure LCR register, 8N1 mode by default */
- s->lcr_reg = MAX3107_LCR_WORD_LEN_8;
- buf[3] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG)
- | s->lcr_reg;
-
- /* 3. Configure MODE 1 register */
- s->mode1_reg = 0;
- /* Enable IRQ pin */
- s->mode1_reg |= MAX3107_MODE1_IRQSEL_BIT;
- /* Disable TX */
- s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT;
- s->tx_enabled = 0;
- /* RX is enabled */
- s->rx_enabled = 1;
- buf[4] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG)
- | s->mode1_reg;
-
- /* 4. Configure MODE 2 register */
- buf[5] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG);
- if (s->loopback) {
- /* Enable loopback */
- buf[5] |= MAX3107_MODE2_LOOPBACK_BIT;
- }
- /* Reset FIFOs */
- buf[5] |= MAX3107_MODE2_FIFORST_BIT;
- s->tx_fifo_empty = 1;
-
- /* 5. Configure FIFO trigger level register */
- buf[6] = (MAX3107_WRITE_BIT | MAX3107_FIFOTRIGLVL_REG);
- /* RX FIFO trigger for 16 words, TX FIFO trigger not used */
- buf[6] |= (MAX3107_FIFOTRIGLVL_RX(16) | MAX3107_FIFOTRIGLVL_TX(0));
-
- /* 6. Configure flow control levels */
- buf[7] = (MAX3107_WRITE_BIT | MAX3107_FLOWLVL_REG);
- /* Flow control halt level 96, resume level 48 */
- buf[7] |= (MAX3107_FLOWLVL_RES(48) | MAX3107_FLOWLVL_HALT(96));
-
- /* 7. Configure flow control */
- buf[8] = (MAX3107_WRITE_BIT | MAX3107_FLOWCTRL_REG);
- /* Enable auto CTS and auto RTS flow control */
- buf[8] |= (MAX3107_FLOWCTRL_AUTOCTS_BIT | MAX3107_FLOWCTRL_AUTORTS_BIT);
-
- /* 8. Configure RX timeout register */
- buf[9] = (MAX3107_WRITE_BIT | MAX3107_RXTO_REG);
- /* Timeout after 48 character intervals */
- buf[9] |= 0x0030;
-
- /* 9. Configure LSR interrupt enable register */
- buf[10] = (MAX3107_WRITE_BIT | MAX3107_LSR_IRQEN_REG);
- /* Enable RX timeout interrupt */
- buf[10] |= MAX3107_LSR_RXTO_BIT;
-
- /* Perform SPI transfer */
- if (max3107_rw(s, (u8 *)buf, NULL, 22))
- dev_err(&s->spi->dev, "SPI transfer for init failed\n");
-
- /* 10. Clear IRQ status register by reading it */
- buf[0] = MAX3107_IRQSTS_REG;
-
- /* 11. Configure interrupt enable register */
- /* Enable LSR interrupt */
- s->irqen_reg = MAX3107_IRQ_LSR_BIT;
- /* Enable RX FIFO interrupt */
- s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT;
- buf[1] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG)
- | s->irqen_reg;
-
- /* 12. Clear FIFO reset that was set in step 6 */
- buf[2] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG);
- if (s->loopback) {
- /* Keep loopback enabled */
- buf[2] |= MAX3107_MODE2_LOOPBACK_BIT;
- }
-
- /* Perform SPI transfer */
- if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 6))
- dev_err(&s->spi->dev, "SPI transfer for init failed\n");
-
-}
-
-/* IRQ handler */
-static irqreturn_t max3107_irq(int irqno, void *dev_id)
-{
- struct max3107_port *s = dev_id;
-
- if (irqno != s->spi->irq) {
- /* Unexpected IRQ */
- return IRQ_NONE;
- }
-
- /* Indicate irq */
- s->handle_irq = 1;
-
- /* Trigger work thread */
- max3107_dowork(s);
-
- return IRQ_HANDLED;
-}
-
-/* HW suspension function
- *
- * Currently autosleep is used to decrease current consumption, alternative
- * approach would be to set the chip to reset mode if UART is not being
- * used but that would mess the GPIOs
- *
- */
-void max3107_hw_susp(struct max3107_port *s, int suspend)
-{
- pr_debug("enter, suspend %d\n", suspend);
-
- if (suspend) {
- /* Suspend requested,
- * enable autosleep to decrease current consumption
- */
- s->suspended = 1;
- max3107_set_sleep(s, MAX3107_ENABLE_AUTOSLEEP);
- } else {
- /* Resume requested,
- * disable autosleep
- */
- s->suspended = 0;
- max3107_set_sleep(s, MAX3107_DISABLE_AUTOSLEEP);
- }
-}
-EXPORT_SYMBOL_GPL(max3107_hw_susp);
-
-/* Modem status IRQ enabling */
-static void max3107_enable_ms(struct uart_port *port)
-{
- /* Modem status not supported */
-}
-
-/* Data send function */
-static void max3107_start_tx(struct uart_port *port)
-{
- struct max3107_port *s = container_of(port, struct max3107_port, port);
-
- /* Trigger work thread for sending data */
- max3107_dowork(s);
-}
-
-/* Function for checking that there is no pending transfers */
-static unsigned int max3107_tx_empty(struct uart_port *port)
-{
- struct max3107_port *s = container_of(port, struct max3107_port, port);
-
- pr_debug("returning %d\n",
- (s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit)));
- return s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit);
-}
-
-/* Function for stopping RX */
-static void max3107_stop_rx(struct uart_port *port)
-{
- struct max3107_port *s = container_of(port, struct max3107_port, port);
- unsigned long flags;
-
- /* Set RX disabled in MODE 1 register */
- spin_lock_irqsave(&s->data_lock, flags);
- s->mode1_reg |= MAX3107_MODE1_RXDIS_BIT;
- s->mode1_commit = 1;
- spin_unlock_irqrestore(&s->data_lock, flags);
- /* Set RX disabled */
- s->rx_enabled = 0;
- /* Trigger work thread for doing the actual configuration change */
- max3107_dowork(s);
-}
-
-/* Function for returning control pin states */
-static unsigned int max3107_get_mctrl(struct uart_port *port)
-{
- /* DCD and DSR are not wired and CTS/RTS is handled automatically
- * so just indicate DSR and CAR asserted
- */
- return TIOCM_DSR | TIOCM_CAR;
-}
-
-/* Function for setting control pin states */
-static void max3107_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
- /* DCD and DSR are not wired and CTS/RTS is hadnled automatically
- * so do nothing
- */
-}
-
-/* Function for configuring UART parameters */
-static void max3107_set_termios(struct uart_port *port,
- struct ktermios *termios,
- struct ktermios *old)
-{
- struct max3107_port *s = container_of(port, struct max3107_port, port);
- struct tty_struct *tty;
- int baud;
- u16 new_lcr = 0;
- u32 new_brg = 0;
- unsigned long flags;
-
- if (!port->state)
- return;
-
- tty = port->state->port.tty;
- if (!tty)
- return;
-
- /* Get new LCR register values */
- /* Word size */
- if ((termios->c_cflag & CSIZE) == CS7)
- new_lcr |= MAX3107_LCR_WORD_LEN_7;
- else
- new_lcr |= MAX3107_LCR_WORD_LEN_8;
-
- /* Parity */
- if (termios->c_cflag & PARENB) {
- new_lcr |= MAX3107_LCR_PARITY_BIT;
- if (!(termios->c_cflag & PARODD))
- new_lcr |= MAX3107_LCR_EVENPARITY_BIT;
- }
-
- /* Stop bits */
- if (termios->c_cflag & CSTOPB) {
- /* 2 stop bits */
- new_lcr |= MAX3107_LCR_STOPLEN_BIT;
- }
-
- /* Mask termios capabilities we don't support */
- termios->c_cflag &= ~CMSPAR;
-
- /* Set status ignore mask */
- s->port.ignore_status_mask = 0;
- if (termios->c_iflag & IGNPAR)
- s->port.ignore_status_mask |= MAX3107_ALL_ERRORS;
-
- /* Set low latency to immediately handle pushed data */
- s->port.state->port.tty->low_latency = 1;
-
- /* Get new baud rate generator configuration */
- baud = tty_get_baud_rate(tty);
-
- spin_lock_irqsave(&s->data_lock, flags);
- new_brg = get_new_brg(baud, s);
- /* if can't find the corrent config, use previous */
- if (!new_brg) {
- baud = s->baud;
- new_brg = s->brg_cfg;
- }
- spin_unlock_irqrestore(&s->data_lock, flags);
- tty_termios_encode_baud_rate(termios, baud, baud);
- s->baud = baud;
-
- /* Update timeout according to new baud rate */
- uart_update_timeout(port, termios->c_cflag, baud);
-
- spin_lock_irqsave(&s->data_lock, flags);
- if (s->lcr_reg != new_lcr) {
- s->lcr_reg = new_lcr;
- s->lcr_commit = 1;
- }
- if (s->brg_cfg != new_brg) {
- s->brg_cfg = new_brg;
- s->brg_commit = 1;
- }
- spin_unlock_irqrestore(&s->data_lock, flags);
-
- /* Trigger work thread for doing the actual configuration change */
- max3107_dowork(s);
-}
-
-/* Port shutdown function */
-static void max3107_shutdown(struct uart_port *port)
-{
- struct max3107_port *s = container_of(port, struct max3107_port, port);
-
- if (s->suspended && s->pdata->hw_suspend)
- s->pdata->hw_suspend(s, 0);
-
- /* Free the interrupt */
- free_irq(s->spi->irq, s);
-
- if (s->workqueue) {
- /* Flush and destroy work queue */
- flush_workqueue(s->workqueue);
- destroy_workqueue(s->workqueue);
- s->workqueue = NULL;
- }
-
- /* Suspend HW */
- if (s->pdata->hw_suspend)
- s->pdata->hw_suspend(s, 1);
-}
-
-/* Port startup function */
-static int max3107_startup(struct uart_port *port)
-{
- struct max3107_port *s = container_of(port, struct max3107_port, port);
-
- /* Initialize work queue */
- s->workqueue = create_freezable_workqueue("max3107");
- if (!s->workqueue) {
- dev_err(&s->spi->dev, "Workqueue creation failed\n");
- return -EBUSY;
- }
- INIT_WORK(&s->work, max3107_work);
-
- /* Setup IRQ */
- if (request_irq(s->spi->irq, max3107_irq, IRQF_TRIGGER_FALLING,
- "max3107", s)) {
- dev_err(&s->spi->dev, "IRQ reguest failed\n");
- destroy_workqueue(s->workqueue);
- s->workqueue = NULL;
- return -EBUSY;
- }
-
- /* Resume HW */
- if (s->pdata->hw_suspend)
- s->pdata->hw_suspend(s, 0);
-
- /* Init registers */
- max3107_register_init(s);
-
- return 0;
-}
-
-/* Port type function */
-static const char *max3107_type(struct uart_port *port)
-{
- struct max3107_port *s = container_of(port, struct max3107_port, port);
- return s->spi->modalias;
-}
-
-/* Port release function */
-static void max3107_release_port(struct uart_port *port)
-{
- /* Do nothing */
-}
-
-/* Port request function */
-static int max3107_request_port(struct uart_port *port)
-{
- /* Do nothing */
- return 0;
-}
-
-/* Port config function */
-static void max3107_config_port(struct uart_port *port, int flags)
-{
- struct max3107_port *s = container_of(port, struct max3107_port, port);
- s->port.type = PORT_MAX3107;
-}
-
-/* Port verify function */
-static int max3107_verify_port(struct uart_port *port,
- struct serial_struct *ser)
-{
- if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3107)
- return 0;
-
- return -EINVAL;
-}
-
-/* Port stop TX function */
-static void max3107_stop_tx(struct uart_port *port)
-{
- /* Do nothing */
-}
-
-/* Port break control function */
-static void max3107_break_ctl(struct uart_port *port, int break_state)
-{
- /* We don't support break control, do nothing */
-}
-
-
-/* Port functions */
-static struct uart_ops max3107_ops = {
- .tx_empty = max3107_tx_empty,
- .set_mctrl = max3107_set_mctrl,
- .get_mctrl = max3107_get_mctrl,
- .stop_tx = max3107_stop_tx,
- .start_tx = max3107_start_tx,
- .stop_rx = max3107_stop_rx,
- .enable_ms = max3107_enable_ms,
- .break_ctl = max3107_break_ctl,
- .startup = max3107_startup,
- .shutdown = max3107_shutdown,
- .set_termios = max3107_set_termios,
- .type = max3107_type,
- .release_port = max3107_release_port,
- .request_port = max3107_request_port,
- .config_port = max3107_config_port,
- .verify_port = max3107_verify_port,
-};
-
-/* UART driver data */
-static struct uart_driver max3107_uart_driver = {
- .owner = THIS_MODULE,
- .driver_name = "ttyMAX",
- .dev_name = "ttyMAX",
- .nr = 1,
-};
-
-static int driver_registered = 0;
-
-
-
-/* 'Generic' platform data */
-static struct max3107_plat generic_plat_data = {
- .loopback = 0,
- .ext_clk = 1,
- .hw_suspend = max3107_hw_susp,
- .polled_mode = 0,
- .poll_time = 0,
-};
-
-
-/*******************************************************************/
-
-/**
- * max3107_probe - SPI bus probe entry point
- * @spi: the spi device
- *
- * SPI wants us to probe this device and if appropriate claim it.
- * Perform any platform specific requirements and then initialise
- * the device.
- */
-
-int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata)
-{
- struct max3107_port *s;
- u16 buf[2]; /* Buffer for SPI transfers */
- int retval;
-
- pr_info("enter max3107 probe\n");
-
- /* Allocate port structure */
- s = kzalloc(sizeof(*s), GFP_KERNEL);
- if (!s) {
- pr_err("Allocating port structure failed\n");
- return -ENOMEM;
- }
-
- s->pdata = pdata;
-
- /* SPI Rx buffer
- * +2 for RX FIFO interrupt
- * disabling and RX level query
- */
- s->rxbuf = kzalloc(sizeof(u16) * (MAX3107_RX_FIFO_SIZE+2), GFP_KERNEL);
- if (!s->rxbuf) {
- pr_err("Allocating RX buffer failed\n");
- retval = -ENOMEM;
- goto err_free4;
- }
- s->rxstr = kzalloc(sizeof(u8) * MAX3107_RX_FIFO_SIZE, GFP_KERNEL);
- if (!s->rxstr) {
- pr_err("Allocating RX buffer failed\n");
- retval = -ENOMEM;
- goto err_free3;
- }
- /* SPI Tx buffer
- * SPI transfer buffer
- * +3 for TX FIFO empty
- * interrupt disabling and
- * enabling and TX enabling
- */
- s->txbuf = kzalloc(sizeof(u16) * MAX3107_TX_FIFO_SIZE + 3, GFP_KERNEL);
- if (!s->txbuf) {
- pr_err("Allocating TX buffer failed\n");
- retval = -ENOMEM;
- goto err_free2;
- }
- /* Initialize shared data lock */
- spin_lock_init(&s->data_lock);
-
- /* SPI intializations */
- dev_set_drvdata(&spi->dev, s);
- spi->mode = SPI_MODE_0;
- spi->dev.platform_data = pdata;
- spi->bits_per_word = 16;
- s->ext_clk = pdata->ext_clk;
- s->loopback = pdata->loopback;
- spi_setup(spi);
- s->spi = spi;
-
- /* Check REV ID to ensure we are talking to what we expect */
- buf[0] = MAX3107_REVID_REG;
- if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
- dev_err(&s->spi->dev, "SPI transfer for REVID read failed\n");
- retval = -EIO;
- goto err_free1;
- }
- if ((buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID1 &&
- (buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID2) {
- dev_err(&s->spi->dev, "REVID %x does not match\n",
- (buf[0] & MAX3107_SPI_RX_DATA_MASK));
- retval = -ENODEV;
- goto err_free1;
- }
-
- /* Disable all interrupts */
- buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG | 0x0000);
- buf[0] |= 0x0000;
-
- /* Configure clock source */
- buf[1] = (MAX3107_WRITE_BIT | MAX3107_CLKSRC_REG);
- if (s->ext_clk) {
- /* External clock */
- buf[1] |= MAX3107_CLKSRC_EXTCLK_BIT;
- }
-
- /* PLL bypass ON */
- buf[1] |= MAX3107_CLKSRC_PLLBYP_BIT;
-
- /* Perform SPI transfer */
- if (max3107_rw(s, (u8 *)buf, NULL, 4)) {
- dev_err(&s->spi->dev, "SPI transfer for init failed\n");
- retval = -EIO;
- goto err_free1;
- }
-
- /* Register UART driver */
- if (!driver_registered) {
- retval = uart_register_driver(&max3107_uart_driver);
- if (retval) {
- dev_err(&s->spi->dev, "Registering UART driver failed\n");
- goto err_free1;
- }
- driver_registered = 1;
- }
-
- /* Initialize UART port data */
- s->port.fifosize = 128;
- s->port.ops = &max3107_ops;
- s->port.line = 0;
- s->port.dev = &spi->dev;
- s->port.uartclk = 9600;
- s->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
- s->port.irq = s->spi->irq;
- s->port.type = PORT_MAX3107;
-
- /* Add UART port */
- retval = uart_add_one_port(&max3107_uart_driver, &s->port);
- if (retval < 0) {
- dev_err(&s->spi->dev, "Adding UART port failed\n");
- goto err_free1;
- }
-
- if (pdata->configure) {
- retval = pdata->configure(s);
- if (retval < 0)
- goto err_free1;
- }
-
- /* Go to suspend mode */
- if (pdata->hw_suspend)
- pdata->hw_suspend(s, 1);
-
- return 0;
-
-err_free1:
- kfree(s->txbuf);
-err_free2:
- kfree(s->rxstr);
-err_free3:
- kfree(s->rxbuf);
-err_free4:
- kfree(s);
- return retval;
-}
-EXPORT_SYMBOL_GPL(max3107_probe);
-
-/* Driver remove function */
-int max3107_remove(struct spi_device *spi)
-{
- struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
- pr_info("enter max3107 remove\n");
-
- /* Remove port */
- if (uart_remove_one_port(&max3107_uart_driver, &s->port))
- dev_warn(&s->spi->dev, "Removing UART port failed\n");
-
-
- /* Free TxRx buffer */
- kfree(s->rxbuf);
- kfree(s->rxstr);
- kfree(s->txbuf);
-
- /* Free port structure */
- kfree(s);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_remove);
-
-/* Driver suspend function */
-int max3107_suspend(struct spi_device *spi, pm_message_t state)
-{
-#ifdef CONFIG_PM
- struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
- pr_debug("enter suspend\n");
-
- /* Suspend UART port */
- uart_suspend_port(&max3107_uart_driver, &s->port);
-
- /* Go to suspend mode */
- if (s->pdata->hw_suspend)
- s->pdata->hw_suspend(s, 1);
-#endif /* CONFIG_PM */
- return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_suspend);
-
-/* Driver resume function */
-int max3107_resume(struct spi_device *spi)
-{
-#ifdef CONFIG_PM
- struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
- pr_debug("enter resume\n");
-
- /* Resume from suspend */
- if (s->pdata->hw_suspend)
- s->pdata->hw_suspend(s, 0);
-
- /* Resume UART port */
- uart_resume_port(&max3107_uart_driver, &s->port);
-#endif /* CONFIG_PM */
- return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_resume);
-
-static int max3107_probe_generic(struct spi_device *spi)
-{
- return max3107_probe(spi, &generic_plat_data);
-}
-
-/* Spi driver data */
-static struct spi_driver max3107_driver = {
- .driver = {
- .name = "max3107",
- .owner = THIS_MODULE,
- },
- .probe = max3107_probe_generic,
- .remove = __devexit_p(max3107_remove),
- .suspend = max3107_suspend,
- .resume = max3107_resume,
-};
-
-/* Driver init function */
-static int __init max3107_init(void)
-{
- pr_info("enter max3107 init\n");
- return spi_register_driver(&max3107_driver);
-}
-
-/* Driver exit function */
-static void __exit max3107_exit(void)
-{
- pr_info("enter max3107 exit\n");
- /* Unregister UART driver */
- if (driver_registered)
- uart_unregister_driver(&max3107_uart_driver);
- spi_unregister_driver(&max3107_driver);
-}
-
-module_init(max3107_init);
-module_exit(max3107_exit);
-
-MODULE_DESCRIPTION("MAX3107 driver");
-MODULE_AUTHOR("Aavamobile");
-MODULE_ALIAS("spi:max3107");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/max3107.h b/drivers/tty/serial/max3107.h
deleted file mode 100644
index 8415fc723b96..000000000000
--- a/drivers/tty/serial/max3107.h
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * max3107.h - spi uart protocol driver header for Maxim 3107
- *
- * Copyright (C) Aavamobile 2009
- * Based on serial_max3100.h by Christian Pellegrin
- *
- * 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.
- */
-
-#ifndef _MAX3107_H
-#define _MAX3107_H
-
-/* Serial error status definitions */
-#define MAX3107_PARITY_ERROR 1
-#define MAX3107_FRAME_ERROR 2
-#define MAX3107_OVERRUN_ERROR 4
-#define MAX3107_ALL_ERRORS (MAX3107_PARITY_ERROR | \
- MAX3107_FRAME_ERROR | \
- MAX3107_OVERRUN_ERROR)
-
-/* GPIO definitions */
-#define MAX3107_GPIO_BASE 88
-#define MAX3107_GPIO_COUNT 4
-
-
-/* GPIO connected to chip's reset pin */
-#define MAX3107_RESET_GPIO 87
-
-
-/* Chip reset delay */
-#define MAX3107_RESET_DELAY 10
-
-/* Chip wakeup delay */
-#define MAX3107_WAKEUP_DELAY 50
-
-
-/* Sleep mode definitions */
-#define MAX3107_DISABLE_FORCED_SLEEP 0
-#define MAX3107_ENABLE_FORCED_SLEEP 1
-#define MAX3107_DISABLE_AUTOSLEEP 2
-#define MAX3107_ENABLE_AUTOSLEEP 3
-
-
-/* Definitions for register access with SPI transfers
- *
- * SPI transfer format:
- *
- * Master to slave bits xzzzzzzzyyyyyyyy
- * Slave to master bits aaaaaaaabbbbbbbb
- *
- * where:
- * x = 0 for reads, 1 for writes
- * z = register address
- * y = new register value if write, 0 if read
- * a = unspecified
- * b = register value if read, unspecified if write
- */
-
-/* SPI speed */
-#define MAX3107_SPI_SPEED (3125000 * 2)
-
-/* Write bit */
-#define MAX3107_WRITE_BIT (1 << 15)
-
-/* SPI TX data mask */
-#define MAX3107_SPI_RX_DATA_MASK (0x00ff)
-
-/* SPI RX data mask */
-#define MAX3107_SPI_TX_DATA_MASK (0x00ff)
-
-/* Register access masks */
-#define MAX3107_RHR_REG (0x0000) /* RX FIFO */
-#define MAX3107_THR_REG (0x0000) /* TX FIFO */
-#define MAX3107_IRQEN_REG (0x0100) /* IRQ enable */
-#define MAX3107_IRQSTS_REG (0x0200) /* IRQ status */
-#define MAX3107_LSR_IRQEN_REG (0x0300) /* LSR IRQ enable */
-#define MAX3107_LSR_IRQSTS_REG (0x0400) /* LSR IRQ status */
-#define MAX3107_SPCHR_IRQEN_REG (0x0500) /* Special char IRQ enable */
-#define MAX3107_SPCHR_IRQSTS_REG (0x0600) /* Special char IRQ status */
-#define MAX3107_STS_IRQEN_REG (0x0700) /* Status IRQ enable */
-#define MAX3107_STS_IRQSTS_REG (0x0800) /* Status IRQ status */
-#define MAX3107_MODE1_REG (0x0900) /* MODE1 */
-#define MAX3107_MODE2_REG (0x0a00) /* MODE2 */
-#define MAX3107_LCR_REG (0x0b00) /* LCR */
-#define MAX3107_RXTO_REG (0x0c00) /* RX timeout */
-#define MAX3107_HDPIXDELAY_REG (0x0d00) /* Auto transceiver delays */
-#define MAX3107_IRDA_REG (0x0e00) /* IRDA settings */
-#define MAX3107_FLOWLVL_REG (0x0f00) /* Flow control levels */
-#define MAX3107_FIFOTRIGLVL_REG (0x1000) /* FIFO IRQ trigger levels */
-#define MAX3107_TXFIFOLVL_REG (0x1100) /* TX FIFO level */
-#define MAX3107_RXFIFOLVL_REG (0x1200) /* RX FIFO level */
-#define MAX3107_FLOWCTRL_REG (0x1300) /* Flow control */
-#define MAX3107_XON1_REG (0x1400) /* XON1 character */
-#define MAX3107_XON2_REG (0x1500) /* XON2 character */
-#define MAX3107_XOFF1_REG (0x1600) /* XOFF1 character */
-#define MAX3107_XOFF2_REG (0x1700) /* XOFF2 character */
-#define MAX3107_GPIOCFG_REG (0x1800) /* GPIO config */
-#define MAX3107_GPIODATA_REG (0x1900) /* GPIO data */
-#define MAX3107_PLLCFG_REG (0x1a00) /* PLL config */
-#define MAX3107_BRGCFG_REG (0x1b00) /* Baud rate generator conf */
-#define MAX3107_BRGDIVLSB_REG (0x1c00) /* Baud rate divisor LSB */
-#define MAX3107_BRGDIVMSB_REG (0x1d00) /* Baud rate divisor MSB */
-#define MAX3107_CLKSRC_REG (0x1e00) /* Clock source */
-#define MAX3107_REVID_REG (0x1f00) /* Revision identification */
-
-/* IRQ register bits */
-#define MAX3107_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */
-#define MAX3107_IRQ_SPCHR_BIT (1 << 1) /* Special char interrupt */
-#define MAX3107_IRQ_STS_BIT (1 << 2) /* Status interrupt */
-#define MAX3107_IRQ_RXFIFO_BIT (1 << 3) /* RX FIFO interrupt */
-#define MAX3107_IRQ_TXFIFO_BIT (1 << 4) /* TX FIFO interrupt */
-#define MAX3107_IRQ_TXEMPTY_BIT (1 << 5) /* TX FIFO empty interrupt */
-#define MAX3107_IRQ_RXEMPTY_BIT (1 << 6) /* RX FIFO empty interrupt */
-#define MAX3107_IRQ_CTS_BIT (1 << 7) /* CTS interrupt */
-
-/* LSR register bits */
-#define MAX3107_LSR_RXTO_BIT (1 << 0) /* RX timeout */
-#define MAX3107_LSR_RXOVR_BIT (1 << 1) /* RX overrun */
-#define MAX3107_LSR_RXPAR_BIT (1 << 2) /* RX parity error */
-#define MAX3107_LSR_FRERR_BIT (1 << 3) /* Frame error */
-#define MAX3107_LSR_RXBRK_BIT (1 << 4) /* RX break */
-#define MAX3107_LSR_RXNOISE_BIT (1 << 5) /* RX noise */
-#define MAX3107_LSR_UNDEF6_BIT (1 << 6) /* Undefined/not used */
-#define MAX3107_LSR_CTS_BIT (1 << 7) /* CTS pin state */
-
-/* Special character register bits */
-#define MAX3107_SPCHR_XON1_BIT (1 << 0) /* XON1 character */
-#define MAX3107_SPCHR_XON2_BIT (1 << 1) /* XON2 character */
-#define MAX3107_SPCHR_XOFF1_BIT (1 << 2) /* XOFF1 character */
-#define MAX3107_SPCHR_XOFF2_BIT (1 << 3) /* XOFF2 character */
-#define MAX3107_SPCHR_BREAK_BIT (1 << 4) /* RX break */
-#define MAX3107_SPCHR_MULTIDROP_BIT (1 << 5) /* 9-bit multidrop addr char */
-#define MAX3107_SPCHR_UNDEF6_BIT (1 << 6) /* Undefined/not used */
-#define MAX3107_SPCHR_UNDEF7_BIT (1 << 7) /* Undefined/not used */
-
-/* Status register bits */
-#define MAX3107_STS_GPIO0_BIT (1 << 0) /* GPIO 0 interrupt */
-#define MAX3107_STS_GPIO1_BIT (1 << 1) /* GPIO 1 interrupt */
-#define MAX3107_STS_GPIO2_BIT (1 << 2) /* GPIO 2 interrupt */
-#define MAX3107_STS_GPIO3_BIT (1 << 3) /* GPIO 3 interrupt */
-#define MAX3107_STS_UNDEF4_BIT (1 << 4) /* Undefined/not used */
-#define MAX3107_STS_CLKREADY_BIT (1 << 5) /* Clock ready */
-#define MAX3107_STS_SLEEP_BIT (1 << 6) /* Sleep interrupt */
-#define MAX3107_STS_UNDEF7_BIT (1 << 7) /* Undefined/not used */
-
-/* MODE1 register bits */
-#define MAX3107_MODE1_RXDIS_BIT (1 << 0) /* RX disable */
-#define MAX3107_MODE1_TXDIS_BIT (1 << 1) /* TX disable */
-#define MAX3107_MODE1_TXHIZ_BIT (1 << 2) /* TX pin three-state */
-#define MAX3107_MODE1_RTSHIZ_BIT (1 << 3) /* RTS pin three-state */
-#define MAX3107_MODE1_TRNSCVCTRL_BIT (1 << 4) /* Transceiver ctrl enable */
-#define MAX3107_MODE1_FORCESLEEP_BIT (1 << 5) /* Force sleep mode */
-#define MAX3107_MODE1_AUTOSLEEP_BIT (1 << 6) /* Auto sleep enable */
-#define MAX3107_MODE1_IRQSEL_BIT (1 << 7) /* IRQ pin enable */
-
-/* MODE2 register bits */
-#define MAX3107_MODE2_RST_BIT (1 << 0) /* Chip reset */
-#define MAX3107_MODE2_FIFORST_BIT (1 << 1) /* FIFO reset */
-#define MAX3107_MODE2_RXTRIGINV_BIT (1 << 2) /* RX FIFO INT invert */
-#define MAX3107_MODE2_RXEMPTINV_BIT (1 << 3) /* RX FIFO empty INT invert */
-#define MAX3107_MODE2_SPCHR_BIT (1 << 4) /* Special chr detect enable */
-#define MAX3107_MODE2_LOOPBACK_BIT (1 << 5) /* Internal loopback enable */
-#define MAX3107_MODE2_MULTIDROP_BIT (1 << 6) /* 9-bit multidrop enable */
-#define MAX3107_MODE2_ECHOSUPR_BIT (1 << 7) /* ECHO suppression enable */
-
-/* LCR register bits */
-#define MAX3107_LCR_LENGTH0_BIT (1 << 0) /* Word length bit 0 */
-#define MAX3107_LCR_LENGTH1_BIT (1 << 1) /* Word length bit 1
- *
- * Word length bits table:
- * 00 -> 5 bit words
- * 01 -> 6 bit words
- * 10 -> 7 bit words
- * 11 -> 8 bit words
- */
-#define MAX3107_LCR_STOPLEN_BIT (1 << 2) /* STOP length bit
- *
- * STOP length bit table:
- * 0 -> 1 stop bit
- * 1 -> 1-1.5 stop bits if
- * word length is 5,
- * 2 stop bits otherwise
- */
-#define MAX3107_LCR_PARITY_BIT (1 << 3) /* Parity bit enable */
-#define MAX3107_LCR_EVENPARITY_BIT (1 << 4) /* Even parity bit enable */
-#define MAX3107_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */
-#define MAX3107_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */
-#define MAX3107_LCR_RTS_BIT (1 << 7) /* RTS pin control */
-#define MAX3107_LCR_WORD_LEN_5 (0x0000)
-#define MAX3107_LCR_WORD_LEN_6 (0x0001)
-#define MAX3107_LCR_WORD_LEN_7 (0x0002)
-#define MAX3107_LCR_WORD_LEN_8 (0x0003)
-
-
-/* IRDA register bits */
-#define MAX3107_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */
-#define MAX3107_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */
-#define MAX3107_IRDA_SHORTIR_BIT (1 << 2) /* Short SIR mode enable */
-#define MAX3107_IRDA_MIR_BIT (1 << 3) /* MIR mode enable */
-#define MAX3107_IRDA_RXINV_BIT (1 << 4) /* RX logic inversion enable */
-#define MAX3107_IRDA_TXINV_BIT (1 << 5) /* TX logic inversion enable */
-#define MAX3107_IRDA_UNDEF6_BIT (1 << 6) /* Undefined/not used */
-#define MAX3107_IRDA_UNDEF7_BIT (1 << 7) /* Undefined/not used */
-
-/* Flow control trigger level register masks */
-#define MAX3107_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */
-#define MAX3107_FLOWLVL_RES_MASK (0x00f0) /* Flow control resume level */
-#define MAX3107_FLOWLVL_HALT(words) ((words/8) & 0x000f)
-#define MAX3107_FLOWLVL_RES(words) (((words/8) & 0x000f) << 4)
-
-/* FIFO interrupt trigger level register masks */
-#define MAX3107_FIFOTRIGLVL_TX_MASK (0x000f) /* TX FIFO trigger level */
-#define MAX3107_FIFOTRIGLVL_RX_MASK (0x00f0) /* RX FIFO trigger level */
-#define MAX3107_FIFOTRIGLVL_TX(words) ((words/8) & 0x000f)
-#define MAX3107_FIFOTRIGLVL_RX(words) (((words/8) & 0x000f) << 4)
-
-/* Flow control register bits */
-#define MAX3107_FLOWCTRL_AUTORTS_BIT (1 << 0) /* Auto RTS flow ctrl enable */
-#define MAX3107_FLOWCTRL_AUTOCTS_BIT (1 << 1) /* Auto CTS flow ctrl enable */
-#define MAX3107_FLOWCTRL_GPIADDR_BIT (1 << 2) /* Enables that GPIO inputs
- * are used in conjunction with
- * XOFF2 for definition of
- * special character */
-#define MAX3107_FLOWCTRL_SWFLOWEN_BIT (1 << 3) /* Auto SW flow ctrl enable */
-#define MAX3107_FLOWCTRL_SWFLOW0_BIT (1 << 4) /* SWFLOW bit 0 */
-#define MAX3107_FLOWCTRL_SWFLOW1_BIT (1 << 5) /* SWFLOW bit 1
- *
- * SWFLOW bits 1 & 0 table:
- * 00 -> no transmitter flow
- * control
- * 01 -> receiver compares
- * XON2 and XOFF2
- * and controls
- * transmitter
- * 10 -> receiver compares
- * XON1 and XOFF1
- * and controls
- * transmitter
- * 11 -> receiver compares
- * XON1, XON2, XOFF1 and
- * XOFF2 and controls
- * transmitter
- */
-#define MAX3107_FLOWCTRL_SWFLOW2_BIT (1 << 6) /* SWFLOW bit 2 */
-#define MAX3107_FLOWCTRL_SWFLOW3_BIT (1 << 7) /* SWFLOW bit 3
- *
- * SWFLOW bits 3 & 2 table:
- * 00 -> no received flow
- * control
- * 01 -> transmitter generates
- * XON2 and XOFF2
- * 10 -> transmitter generates
- * XON1 and XOFF1
- * 11 -> transmitter generates
- * XON1, XON2, XOFF1 and
- * XOFF2
- */
-
-/* GPIO configuration register bits */
-#define MAX3107_GPIOCFG_GP0OUT_BIT (1 << 0) /* GPIO 0 output enable */
-#define MAX3107_GPIOCFG_GP1OUT_BIT (1 << 1) /* GPIO 1 output enable */
-#define MAX3107_GPIOCFG_GP2OUT_BIT (1 << 2) /* GPIO 2 output enable */
-#define MAX3107_GPIOCFG_GP3OUT_BIT (1 << 3) /* GPIO 3 output enable */
-#define MAX3107_GPIOCFG_GP0OD_BIT (1 << 4) /* GPIO 0 open-drain enable */
-#define MAX3107_GPIOCFG_GP1OD_BIT (1 << 5) /* GPIO 1 open-drain enable */
-#define MAX3107_GPIOCFG_GP2OD_BIT (1 << 6) /* GPIO 2 open-drain enable */
-#define MAX3107_GPIOCFG_GP3OD_BIT (1 << 7) /* GPIO 3 open-drain enable */
-
-/* GPIO DATA register bits */
-#define MAX3107_GPIODATA_GP0OUT_BIT (1 << 0) /* GPIO 0 output value */
-#define MAX3107_GPIODATA_GP1OUT_BIT (1 << 1) /* GPIO 1 output value */
-#define MAX3107_GPIODATA_GP2OUT_BIT (1 << 2) /* GPIO 2 output value */
-#define MAX3107_GPIODATA_GP3OUT_BIT (1 << 3) /* GPIO 3 output value */
-#define MAX3107_GPIODATA_GP0IN_BIT (1 << 4) /* GPIO 0 input value */
-#define MAX3107_GPIODATA_GP1IN_BIT (1 << 5) /* GPIO 1 input value */
-#define MAX3107_GPIODATA_GP2IN_BIT (1 << 6) /* GPIO 2 input value */
-#define MAX3107_GPIODATA_GP3IN_BIT (1 << 7) /* GPIO 3 input value */
-
-/* PLL configuration register masks */
-#define MAX3107_PLLCFG_PREDIV_MASK (0x003f) /* PLL predivision value */
-#define MAX3107_PLLCFG_PLLFACTOR_MASK (0x00c0) /* PLL multiplication factor */
-
-/* Baud rate generator configuration register masks and bits */
-#define MAX3107_BRGCFG_FRACT_MASK (0x000f) /* Fractional portion of
- * Baud rate generator divisor
- */
-#define MAX3107_BRGCFG_2XMODE_BIT (1 << 4) /* Double baud rate */
-#define MAX3107_BRGCFG_4XMODE_BIT (1 << 5) /* Quadruple baud rate */
-#define MAX3107_BRGCFG_UNDEF6_BIT (1 << 6) /* Undefined/not used */
-#define MAX3107_BRGCFG_UNDEF7_BIT (1 << 7) /* Undefined/not used */
-
-/* Clock source register bits */
-#define MAX3107_CLKSRC_INTOSC_BIT (1 << 0) /* Internal osc enable */
-#define MAX3107_CLKSRC_CRYST_BIT (1 << 1) /* Crystal osc enable */
-#define MAX3107_CLKSRC_PLL_BIT (1 << 2) /* PLL enable */
-#define MAX3107_CLKSRC_PLLBYP_BIT (1 << 3) /* PLL bypass */
-#define MAX3107_CLKSRC_EXTCLK_BIT (1 << 4) /* External clock enable */
-#define MAX3107_CLKSRC_UNDEF5_BIT (1 << 5) /* Undefined/not used */
-#define MAX3107_CLKSRC_UNDEF6_BIT (1 << 6) /* Undefined/not used */
-#define MAX3107_CLKSRC_CLK2RTS_BIT (1 << 7) /* Baud clk to RTS pin */
-
-
-/* HW definitions */
-#define MAX3107_RX_FIFO_SIZE 128
-#define MAX3107_TX_FIFO_SIZE 128
-#define MAX3107_REVID1 0x00a0
-#define MAX3107_REVID2 0x00a1
-
-
-/* Baud rate generator configuration values for external clock 13MHz */
-#define MAX3107_BRG13_B300 (0x0A9400 | 0x05)
-#define MAX3107_BRG13_B600 (0x054A00 | 0x03)
-#define MAX3107_BRG13_B1200 (0x02A500 | 0x01)
-#define MAX3107_BRG13_B2400 (0x015200 | 0x09)
-#define MAX3107_BRG13_B4800 (0x00A900 | 0x04)
-#define MAX3107_BRG13_B9600 (0x005400 | 0x0A)
-#define MAX3107_BRG13_B19200 (0x002A00 | 0x05)
-#define MAX3107_BRG13_B38400 (0x001500 | 0x03)
-#define MAX3107_BRG13_B57600 (0x000E00 | 0x02)
-#define MAX3107_BRG13_B115200 (0x000700 | 0x01)
-#define MAX3107_BRG13_B230400 (0x000300 | 0x08)
-#define MAX3107_BRG13_B460800 (0x000100 | 0x0c)
-#define MAX3107_BRG13_B921600 (0x000100 | 0x1c)
-
-/* Baud rate generator configuration values for external clock 26MHz */
-#define MAX3107_BRG26_B300 (0x152800 | 0x0A)
-#define MAX3107_BRG26_B600 (0x0A9400 | 0x05)
-#define MAX3107_BRG26_B1200 (0x054A00 | 0x03)
-#define MAX3107_BRG26_B2400 (0x02A500 | 0x01)
-#define MAX3107_BRG26_B4800 (0x015200 | 0x09)
-#define MAX3107_BRG26_B9600 (0x00A900 | 0x04)
-#define MAX3107_BRG26_B19200 (0x005400 | 0x0A)
-#define MAX3107_BRG26_B38400 (0x002A00 | 0x05)
-#define MAX3107_BRG26_B57600 (0x001C00 | 0x03)
-#define MAX3107_BRG26_B115200 (0x000E00 | 0x02)
-#define MAX3107_BRG26_B230400 (0x000700 | 0x01)
-#define MAX3107_BRG26_B460800 (0x000300 | 0x08)
-#define MAX3107_BRG26_B921600 (0x000100 | 0x0C)
-
-/* Baud rate generator configuration values for internal clock */
-#define MAX3107_BRG13_IB300 (0x008000 | 0x00)
-#define MAX3107_BRG13_IB600 (0x004000 | 0x00)
-#define MAX3107_BRG13_IB1200 (0x002000 | 0x00)
-#define MAX3107_BRG13_IB2400 (0x001000 | 0x00)
-#define MAX3107_BRG13_IB4800 (0x000800 | 0x00)
-#define MAX3107_BRG13_IB9600 (0x000400 | 0x00)
-#define MAX3107_BRG13_IB19200 (0x000200 | 0x00)
-#define MAX3107_BRG13_IB38400 (0x000100 | 0x00)
-#define MAX3107_BRG13_IB57600 (0x000000 | 0x0B)
-#define MAX3107_BRG13_IB115200 (0x000000 | 0x05)
-#define MAX3107_BRG13_IB230400 (0x000000 | 0x03)
-#define MAX3107_BRG13_IB460800 (0x000000 | 0x00)
-#define MAX3107_BRG13_IB921600 (0x000000 | 0x00)
-
-
-struct baud_table {
- int baud;
- u32 new_brg;
-};
-
-struct max3107_port {
- /* UART port structure */
- struct uart_port port;
-
- /* SPI device structure */
- struct spi_device *spi;
-
-#if defined(CONFIG_GPIOLIB)
- /* GPIO chip structure */
- struct gpio_chip chip;
-#endif
-
- /* Workqueue that does all the magic */
- struct workqueue_struct *workqueue;
- struct work_struct work;
-
- /* Lock for shared data */
- spinlock_t data_lock;
-
- /* Device configuration */
- int ext_clk; /* 1 if external clock used */
- int loopback; /* Current loopback mode state */
- int baud; /* Current baud rate */
-
- /* State flags */
- int suspended; /* Indicates suspend mode */
- int tx_fifo_empty; /* Flag for TX FIFO state */
- int rx_enabled; /* Flag for receiver state */
- int tx_enabled; /* Flag for transmitter state */
-
- u16 irqen_reg; /* Current IRQ enable register value */
- /* Shared data */
- u16 mode1_reg; /* Current mode1 register value*/
- int mode1_commit; /* Flag for setting new mode1 register value */
- u16 lcr_reg; /* Current LCR register value */
- int lcr_commit; /* Flag for setting new LCR register value */
- u32 brg_cfg; /* Current Baud rate generator config */
- int brg_commit; /* Flag for setting new baud rate generator
- * config
- */
- struct baud_table *baud_tbl;
- int handle_irq; /* Indicates that IRQ should be handled */
-
- /* Rx buffer and str*/
- u16 *rxbuf;
- u8 *rxstr;
- /* Tx buffer*/
- u16 *txbuf;
-
- struct max3107_plat *pdata; /* Platform data */
-};
-
-/* Platform data structure */
-struct max3107_plat {
- /* Loopback mode enable */
- int loopback;
- /* External clock enable */
- int ext_clk;
- /* Called during the register initialisation */
- void (*init)(struct max3107_port *s);
- /* Called when the port is found and configured */
- int (*configure)(struct max3107_port *s);
- /* HW suspend function */
- void (*hw_suspend) (struct max3107_port *s, int suspend);
- /* Polling mode enable */
- int polled_mode;
- /* Polling period if polling mode enabled */
- int poll_time;
-};
-
-extern int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len);
-extern void max3107_hw_susp(struct max3107_port *s, int suspend);
-extern int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata);
-extern int max3107_remove(struct spi_device *spi);
-extern int max3107_suspend(struct spi_device *spi, pm_message_t state);
-extern int max3107_resume(struct spi_device *spi);
-
-#endif /* _LINUX_SERIAL_MAX3107_H */
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
new file mode 100644
index 000000000000..2bc28a59d385
--- /dev/null
+++ b/drivers/tty/serial/max310x.c
@@ -0,0 +1,1260 @@
+/*
+ * Maxim (Dallas) MAX3107/8 serial driver
+ *
+ * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * Based on max3100.c, by Christian Pellegrin <chripell@evolware.org>
+ * Based on max3110.c, by Feng Tang <feng.tang@intel.com>
+ * Based on max3107.c, by Aavamobile
+ *
+ * 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.
+ */
+
+/* TODO: MAX3109 support (Dual) */
+/* TODO: MAX14830 support (Quad) */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/regmap.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_data/max310x.h>
+
+#define MAX310X_MAJOR 204
+#define MAX310X_MINOR 209
+
+/* MAX310X register definitions */
+#define MAX310X_RHR_REG (0x00) /* RX FIFO */
+#define MAX310X_THR_REG (0x00) /* TX FIFO */
+#define MAX310X_IRQEN_REG (0x01) /* IRQ enable */
+#define MAX310X_IRQSTS_REG (0x02) /* IRQ status */
+#define MAX310X_LSR_IRQEN_REG (0x03) /* LSR IRQ enable */
+#define MAX310X_LSR_IRQSTS_REG (0x04) /* LSR IRQ status */
+#define MAX310X_SPCHR_IRQEN_REG (0x05) /* Special char IRQ enable */
+#define MAX310X_SPCHR_IRQSTS_REG (0x06) /* Special char IRQ status */
+#define MAX310X_STS_IRQEN_REG (0x07) /* Status IRQ enable */
+#define MAX310X_STS_IRQSTS_REG (0x08) /* Status IRQ status */
+#define MAX310X_MODE1_REG (0x09) /* MODE1 */
+#define MAX310X_MODE2_REG (0x0a) /* MODE2 */
+#define MAX310X_LCR_REG (0x0b) /* LCR */
+#define MAX310X_RXTO_REG (0x0c) /* RX timeout */
+#define MAX310X_HDPIXDELAY_REG (0x0d) /* Auto transceiver delays */
+#define MAX310X_IRDA_REG (0x0e) /* IRDA settings */
+#define MAX310X_FLOWLVL_REG (0x0f) /* Flow control levels */
+#define MAX310X_FIFOTRIGLVL_REG (0x10) /* FIFO IRQ trigger levels */
+#define MAX310X_TXFIFOLVL_REG (0x11) /* TX FIFO level */
+#define MAX310X_RXFIFOLVL_REG (0x12) /* RX FIFO level */
+#define MAX310X_FLOWCTRL_REG (0x13) /* Flow control */
+#define MAX310X_XON1_REG (0x14) /* XON1 character */
+#define MAX310X_XON2_REG (0x15) /* XON2 character */
+#define MAX310X_XOFF1_REG (0x16) /* XOFF1 character */
+#define MAX310X_XOFF2_REG (0x17) /* XOFF2 character */
+#define MAX310X_GPIOCFG_REG (0x18) /* GPIO config */
+#define MAX310X_GPIODATA_REG (0x19) /* GPIO data */
+#define MAX310X_PLLCFG_REG (0x1a) /* PLL config */
+#define MAX310X_BRGCFG_REG (0x1b) /* Baud rate generator conf */
+#define MAX310X_BRGDIVLSB_REG (0x1c) /* Baud rate divisor LSB */
+#define MAX310X_BRGDIVMSB_REG (0x1d) /* Baud rate divisor MSB */
+#define MAX310X_CLKSRC_REG (0x1e) /* Clock source */
+/* Only present in MAX3107 */
+#define MAX3107_REVID_REG (0x1f) /* Revision identification */
+
+/* IRQ register bits */
+#define MAX310X_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */
+#define MAX310X_IRQ_SPCHR_BIT (1 << 1) /* Special char interrupt */
+#define MAX310X_IRQ_STS_BIT (1 << 2) /* Status interrupt */
+#define MAX310X_IRQ_RXFIFO_BIT (1 << 3) /* RX FIFO interrupt */
+#define MAX310X_IRQ_TXFIFO_BIT (1 << 4) /* TX FIFO interrupt */
+#define MAX310X_IRQ_TXEMPTY_BIT (1 << 5) /* TX FIFO empty interrupt */
+#define MAX310X_IRQ_RXEMPTY_BIT (1 << 6) /* RX FIFO empty interrupt */
+#define MAX310X_IRQ_CTS_BIT (1 << 7) /* CTS interrupt */
+
+/* LSR register bits */
+#define MAX310X_LSR_RXTO_BIT (1 << 0) /* RX timeout */
+#define MAX310X_LSR_RXOVR_BIT (1 << 1) /* RX overrun */
+#define MAX310X_LSR_RXPAR_BIT (1 << 2) /* RX parity error */
+#define MAX310X_LSR_FRERR_BIT (1 << 3) /* Frame error */
+#define MAX310X_LSR_RXBRK_BIT (1 << 4) /* RX break */
+#define MAX310X_LSR_RXNOISE_BIT (1 << 5) /* RX noise */
+#define MAX310X_LSR_CTS_BIT (1 << 7) /* CTS pin state */
+
+/* Special character register bits */
+#define MAX310X_SPCHR_XON1_BIT (1 << 0) /* XON1 character */
+#define MAX310X_SPCHR_XON2_BIT (1 << 1) /* XON2 character */
+#define MAX310X_SPCHR_XOFF1_BIT (1 << 2) /* XOFF1 character */
+#define MAX310X_SPCHR_XOFF2_BIT (1 << 3) /* XOFF2 character */
+#define MAX310X_SPCHR_BREAK_BIT (1 << 4) /* RX break */
+#define MAX310X_SPCHR_MULTIDROP_BIT (1 << 5) /* 9-bit multidrop addr char */
+
+/* Status register bits */
+#define MAX310X_STS_GPIO0_BIT (1 << 0) /* GPIO 0 interrupt */
+#define MAX310X_STS_GPIO1_BIT (1 << 1) /* GPIO 1 interrupt */
+#define MAX310X_STS_GPIO2_BIT (1 << 2) /* GPIO 2 interrupt */
+#define MAX310X_STS_GPIO3_BIT (1 << 3) /* GPIO 3 interrupt */
+#define MAX310X_STS_CLKREADY_BIT (1 << 5) /* Clock ready */
+#define MAX310X_STS_SLEEP_BIT (1 << 6) /* Sleep interrupt */
+
+/* MODE1 register bits */
+#define MAX310X_MODE1_RXDIS_BIT (1 << 0) /* RX disable */
+#define MAX310X_MODE1_TXDIS_BIT (1 << 1) /* TX disable */
+#define MAX310X_MODE1_TXHIZ_BIT (1 << 2) /* TX pin three-state */
+#define MAX310X_MODE1_RTSHIZ_BIT (1 << 3) /* RTS pin three-state */
+#define MAX310X_MODE1_TRNSCVCTRL_BIT (1 << 4) /* Transceiver ctrl enable */
+#define MAX310X_MODE1_FORCESLEEP_BIT (1 << 5) /* Force sleep mode */
+#define MAX310X_MODE1_AUTOSLEEP_BIT (1 << 6) /* Auto sleep enable */
+#define MAX310X_MODE1_IRQSEL_BIT (1 << 7) /* IRQ pin enable */
+
+/* MODE2 register bits */
+#define MAX310X_MODE2_RST_BIT (1 << 0) /* Chip reset */
+#define MAX310X_MODE2_FIFORST_BIT (1 << 1) /* FIFO reset */
+#define MAX310X_MODE2_RXTRIGINV_BIT (1 << 2) /* RX FIFO INT invert */
+#define MAX310X_MODE2_RXEMPTINV_BIT (1 << 3) /* RX FIFO empty INT invert */
+#define MAX310X_MODE2_SPCHR_BIT (1 << 4) /* Special chr detect enable */
+#define MAX310X_MODE2_LOOPBACK_BIT (1 << 5) /* Internal loopback enable */
+#define MAX310X_MODE2_MULTIDROP_BIT (1 << 6) /* 9-bit multidrop enable */
+#define MAX310X_MODE2_ECHOSUPR_BIT (1 << 7) /* ECHO suppression enable */
+
+/* LCR register bits */
+#define MAX310X_LCR_LENGTH0_BIT (1 << 0) /* Word length bit 0 */
+#define MAX310X_LCR_LENGTH1_BIT (1 << 1) /* Word length bit 1
+ *
+ * Word length bits table:
+ * 00 -> 5 bit words
+ * 01 -> 6 bit words
+ * 10 -> 7 bit words
+ * 11 -> 8 bit words
+ */
+#define MAX310X_LCR_STOPLEN_BIT (1 << 2) /* STOP length bit
+ *
+ * STOP length bit table:
+ * 0 -> 1 stop bit
+ * 1 -> 1-1.5 stop bits if
+ * word length is 5,
+ * 2 stop bits otherwise
+ */
+#define MAX310X_LCR_PARITY_BIT (1 << 3) /* Parity bit enable */
+#define MAX310X_LCR_EVENPARITY_BIT (1 << 4) /* Even parity bit enable */
+#define MAX310X_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */
+#define MAX310X_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */
+#define MAX310X_LCR_RTS_BIT (1 << 7) /* RTS pin control */
+#define MAX310X_LCR_WORD_LEN_5 (0x00)
+#define MAX310X_LCR_WORD_LEN_6 (0x01)
+#define MAX310X_LCR_WORD_LEN_7 (0x02)
+#define MAX310X_LCR_WORD_LEN_8 (0x03)
+
+/* IRDA register bits */
+#define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */
+#define MAX310X_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */
+#define MAX310X_IRDA_SHORTIR_BIT (1 << 2) /* Short SIR mode enable */
+#define MAX310X_IRDA_MIR_BIT (1 << 3) /* MIR mode enable */
+#define MAX310X_IRDA_RXINV_BIT (1 << 4) /* RX logic inversion enable */
+#define MAX310X_IRDA_TXINV_BIT (1 << 5) /* TX logic inversion enable */
+
+/* Flow control trigger level register masks */
+#define MAX310X_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */
+#define MAX310X_FLOWLVL_RES_MASK (0x00f0) /* Flow control resume level */
+#define MAX310X_FLOWLVL_HALT(words) ((words / 8) & 0x0f)
+#define MAX310X_FLOWLVL_RES(words) (((words / 8) & 0x0f) << 4)
+
+/* FIFO interrupt trigger level register masks */
+#define MAX310X_FIFOTRIGLVL_TX_MASK (0x0f) /* TX FIFO trigger level */
+#define MAX310X_FIFOTRIGLVL_RX_MASK (0xf0) /* RX FIFO trigger level */
+#define MAX310X_FIFOTRIGLVL_TX(words) ((words / 8) & 0x0f)
+#define MAX310X_FIFOTRIGLVL_RX(words) (((words / 8) & 0x0f) << 4)
+
+/* Flow control register bits */
+#define MAX310X_FLOWCTRL_AUTORTS_BIT (1 << 0) /* Auto RTS flow ctrl enable */
+#define MAX310X_FLOWCTRL_AUTOCTS_BIT (1 << 1) /* Auto CTS flow ctrl enable */
+#define MAX310X_FLOWCTRL_GPIADDR_BIT (1 << 2) /* Enables that GPIO inputs
+ * are used in conjunction with
+ * XOFF2 for definition of
+ * special character */
+#define MAX310X_FLOWCTRL_SWFLOWEN_BIT (1 << 3) /* Auto SW flow ctrl enable */
+#define MAX310X_FLOWCTRL_SWFLOW0_BIT (1 << 4) /* SWFLOW bit 0 */
+#define MAX310X_FLOWCTRL_SWFLOW1_BIT (1 << 5) /* SWFLOW bit 1
+ *
+ * SWFLOW bits 1 & 0 table:
+ * 00 -> no transmitter flow
+ * control
+ * 01 -> receiver compares
+ * XON2 and XOFF2
+ * and controls
+ * transmitter
+ * 10 -> receiver compares
+ * XON1 and XOFF1
+ * and controls
+ * transmitter
+ * 11 -> receiver compares
+ * XON1, XON2, XOFF1 and
+ * XOFF2 and controls
+ * transmitter
+ */
+#define MAX310X_FLOWCTRL_SWFLOW2_BIT (1 << 6) /* SWFLOW bit 2 */
+#define MAX310X_FLOWCTRL_SWFLOW3_BIT (1 << 7) /* SWFLOW bit 3
+ *
+ * SWFLOW bits 3 & 2 table:
+ * 00 -> no received flow
+ * control
+ * 01 -> transmitter generates
+ * XON2 and XOFF2
+ * 10 -> transmitter generates
+ * XON1 and XOFF1
+ * 11 -> transmitter generates
+ * XON1, XON2, XOFF1 and
+ * XOFF2
+ */
+
+/* GPIO configuration register bits */
+#define MAX310X_GPIOCFG_GP0OUT_BIT (1 << 0) /* GPIO 0 output enable */
+#define MAX310X_GPIOCFG_GP1OUT_BIT (1 << 1) /* GPIO 1 output enable */
+#define MAX310X_GPIOCFG_GP2OUT_BIT (1 << 2) /* GPIO 2 output enable */
+#define MAX310X_GPIOCFG_GP3OUT_BIT (1 << 3) /* GPIO 3 output enable */
+#define MAX310X_GPIOCFG_GP0OD_BIT (1 << 4) /* GPIO 0 open-drain enable */
+#define MAX310X_GPIOCFG_GP1OD_BIT (1 << 5) /* GPIO 1 open-drain enable */
+#define MAX310X_GPIOCFG_GP2OD_BIT (1 << 6) /* GPIO 2 open-drain enable */
+#define MAX310X_GPIOCFG_GP3OD_BIT (1 << 7) /* GPIO 3 open-drain enable */
+
+/* GPIO DATA register bits */
+#define MAX310X_GPIODATA_GP0OUT_BIT (1 << 0) /* GPIO 0 output value */
+#define MAX310X_GPIODATA_GP1OUT_BIT (1 << 1) /* GPIO 1 output value */
+#define MAX310X_GPIODATA_GP2OUT_BIT (1 << 2) /* GPIO 2 output value */
+#define MAX310X_GPIODATA_GP3OUT_BIT (1 << 3) /* GPIO 3 output value */
+#define MAX310X_GPIODATA_GP0IN_BIT (1 << 4) /* GPIO 0 input value */
+#define MAX310X_GPIODATA_GP1IN_BIT (1 << 5) /* GPIO 1 input value */
+#define MAX310X_GPIODATA_GP2IN_BIT (1 << 6) /* GPIO 2 input value */
+#define MAX310X_GPIODATA_GP3IN_BIT (1 << 7) /* GPIO 3 input value */
+
+/* PLL configuration register masks */
+#define MAX310X_PLLCFG_PREDIV_MASK (0x3f) /* PLL predivision value */
+#define MAX310X_PLLCFG_PLLFACTOR_MASK (0xc0) /* PLL multiplication factor */
+
+/* Baud rate generator configuration register bits */
+#define MAX310X_BRGCFG_2XMODE_BIT (1 << 4) /* Double baud rate */
+#define MAX310X_BRGCFG_4XMODE_BIT (1 << 5) /* Quadruple baud rate */
+
+/* Clock source register bits */
+#define MAX310X_CLKSRC_CRYST_BIT (1 << 1) /* Crystal osc enable */
+#define MAX310X_CLKSRC_PLL_BIT (1 << 2) /* PLL enable */
+#define MAX310X_CLKSRC_PLLBYP_BIT (1 << 3) /* PLL bypass */
+#define MAX310X_CLKSRC_EXTCLK_BIT (1 << 4) /* External clock enable */
+#define MAX310X_CLKSRC_CLK2RTS_BIT (1 << 7) /* Baud clk to RTS pin */
+
+/* Misc definitions */
+#define MAX310X_FIFO_SIZE (128)
+
+/* MAX3107 specific */
+#define MAX3107_REV_ID (0xa0)
+#define MAX3107_REV_MASK (0xfe)
+
+/* IRQ status bits definitions */
+#define MAX310X_IRQ_TX (MAX310X_IRQ_TXFIFO_BIT | \
+ MAX310X_IRQ_TXEMPTY_BIT)
+#define MAX310X_IRQ_RX (MAX310X_IRQ_RXFIFO_BIT | \
+ MAX310X_IRQ_RXEMPTY_BIT)
+
+/* Supported chip types */
+enum {
+ MAX310X_TYPE_MAX3107 = 3107,
+ MAX310X_TYPE_MAX3108 = 3108,
+};
+
+struct max310x_port {
+ struct uart_driver uart;
+ struct uart_port port;
+
+ const char *name;
+ int uartclk;
+
+ unsigned int nr_gpio;
+#ifdef CONFIG_GPIOLIB
+ struct gpio_chip gpio;
+#endif
+
+ struct regmap *regmap;
+ struct regmap_config regcfg;
+
+ struct workqueue_struct *wq;
+ struct work_struct tx_work;
+
+ struct mutex max310x_mutex;
+
+ struct max310x_pdata *pdata;
+};
+
+static bool max3107_8_reg_writeable(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX310X_IRQSTS_REG:
+ case MAX310X_LSR_IRQSTS_REG:
+ case MAX310X_SPCHR_IRQSTS_REG:
+ case MAX310X_STS_IRQSTS_REG:
+ case MAX310X_TXFIFOLVL_REG:
+ case MAX310X_RXFIFOLVL_REG:
+ case MAX3107_REVID_REG: /* Only available on MAX3107 */
+ return false;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+static bool max310x_reg_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX310X_RHR_REG:
+ case MAX310X_IRQSTS_REG:
+ case MAX310X_LSR_IRQSTS_REG:
+ case MAX310X_SPCHR_IRQSTS_REG:
+ case MAX310X_STS_IRQSTS_REG:
+ case MAX310X_TXFIFOLVL_REG:
+ case MAX310X_RXFIFOLVL_REG:
+ case MAX310X_GPIODATA_REG:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static bool max310x_reg_precious(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX310X_RHR_REG:
+ case MAX310X_IRQSTS_REG:
+ case MAX310X_SPCHR_IRQSTS_REG:
+ case MAX310X_STS_IRQSTS_REG:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static void max310x_set_baud(struct max310x_port *s, int baud)
+{
+ unsigned int mode = 0, div = s->uartclk / baud;
+
+ if (!(div / 16)) {
+ /* Mode x2 */
+ mode = MAX310X_BRGCFG_2XMODE_BIT;
+ div = (s->uartclk * 2) / baud;
+ }
+
+ if (!(div / 16)) {
+ /* Mode x4 */
+ mode = MAX310X_BRGCFG_4XMODE_BIT;
+ div = (s->uartclk * 4) / baud;
+ }
+
+ regmap_write(s->regmap, MAX310X_BRGDIVMSB_REG,
+ ((div / 16) >> 8) & 0xff);
+ regmap_write(s->regmap, MAX310X_BRGDIVLSB_REG, (div / 16) & 0xff);
+ regmap_write(s->regmap, MAX310X_BRGCFG_REG, (div % 16) | mode);
+}
+
+static void max310x_wait_pll(struct max310x_port *s)
+{
+ int tryes = 1000;
+
+ /* Wait for PLL only if crystal is used */
+ if (!(s->pdata->driver_flags & MAX310X_EXT_CLK)) {
+ unsigned int sts = 0;
+
+ while (tryes--) {
+ regmap_read(s->regmap, MAX310X_STS_IRQSTS_REG, &sts);
+ if (sts & MAX310X_STS_CLKREADY_BIT)
+ break;
+ }
+ }
+}
+
+static int __devinit max310x_update_best_err(unsigned long f, long *besterr)
+{
+ /* Use baudrate 115200 for calculate error */
+ long err = f % (115200 * 16);
+
+ if ((*besterr < 0) || (*besterr > err)) {
+ *besterr = err;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int __devinit max310x_set_ref_clk(struct max310x_port *s)
+{
+ unsigned int div, clksrc, pllcfg = 0;
+ long besterr = -1;
+ unsigned long fdiv, fmul, bestfreq = s->pdata->frequency;
+
+ /* First, update error without PLL */
+ max310x_update_best_err(s->pdata->frequency, &besterr);
+
+ /* Try all possible PLL dividers */
+ for (div = 1; (div <= 63) && besterr; div++) {
+ fdiv = DIV_ROUND_CLOSEST(s->pdata->frequency, div);
+
+ /* Try multiplier 6 */
+ fmul = fdiv * 6;
+ if ((fdiv >= 500000) && (fdiv <= 800000))
+ if (!max310x_update_best_err(fmul, &besterr)) {
+ pllcfg = (0 << 6) | div;
+ bestfreq = fmul;
+ }
+ /* Try multiplier 48 */
+ fmul = fdiv * 48;
+ if ((fdiv >= 850000) && (fdiv <= 1200000))
+ if (!max310x_update_best_err(fmul, &besterr)) {
+ pllcfg = (1 << 6) | div;
+ bestfreq = fmul;
+ }
+ /* Try multiplier 96 */
+ fmul = fdiv * 96;
+ if ((fdiv >= 425000) && (fdiv <= 1000000))
+ if (!max310x_update_best_err(fmul, &besterr)) {
+ pllcfg = (2 << 6) | div;
+ bestfreq = fmul;
+ }
+ /* Try multiplier 144 */
+ fmul = fdiv * 144;
+ if ((fdiv >= 390000) && (fdiv <= 667000))
+ if (!max310x_update_best_err(fmul, &besterr)) {
+ pllcfg = (3 << 6) | div;
+ bestfreq = fmul;
+ }
+ }
+
+ /* Configure clock source */
+ if (s->pdata->driver_flags & MAX310X_EXT_CLK)
+ clksrc = MAX310X_CLKSRC_EXTCLK_BIT;
+ else
+ clksrc = MAX310X_CLKSRC_CRYST_BIT;
+
+ /* Configure PLL */
+ if (pllcfg) {
+ clksrc |= MAX310X_CLKSRC_PLL_BIT;
+ regmap_write(s->regmap, MAX310X_PLLCFG_REG, pllcfg);
+ } else
+ clksrc |= MAX310X_CLKSRC_PLLBYP_BIT;
+
+ regmap_write(s->regmap, MAX310X_CLKSRC_REG, clksrc);
+
+ if (pllcfg)
+ max310x_wait_pll(s);
+
+ dev_dbg(s->port.dev, "Reference clock set to %lu Hz\n", bestfreq);
+
+ return (int)bestfreq;
+}
+
+static void max310x_handle_rx(struct max310x_port *s, unsigned int rxlen)
+{
+ unsigned int sts = 0, ch = 0, flag;
+ struct tty_struct *tty = tty_port_tty_get(&s->port.state->port);
+
+ if (!tty)
+ return;
+
+ if (unlikely(rxlen >= MAX310X_FIFO_SIZE)) {
+ dev_warn(s->port.dev, "Possible RX FIFO overrun %d\n", rxlen);
+ /* Ensure sanity of RX level */
+ rxlen = MAX310X_FIFO_SIZE;
+ }
+
+ dev_dbg(s->port.dev, "RX Len = %u\n", rxlen);
+
+ while (rxlen--) {
+ regmap_read(s->regmap, MAX310X_RHR_REG, &ch);
+ regmap_read(s->regmap, MAX310X_LSR_IRQSTS_REG, &sts);
+
+ sts &= MAX310X_LSR_RXPAR_BIT | MAX310X_LSR_FRERR_BIT |
+ MAX310X_LSR_RXOVR_BIT | MAX310X_LSR_RXBRK_BIT;
+
+ s->port.icount.rx++;
+ flag = TTY_NORMAL;
+
+ if (unlikely(sts)) {
+ if (sts & MAX310X_LSR_RXBRK_BIT) {
+ s->port.icount.brk++;
+ if (uart_handle_break(&s->port))
+ continue;
+ } else if (sts & MAX310X_LSR_RXPAR_BIT)
+ s->port.icount.parity++;
+ else if (sts & MAX310X_LSR_FRERR_BIT)
+ s->port.icount.frame++;
+ else if (sts & MAX310X_LSR_RXOVR_BIT)
+ s->port.icount.overrun++;
+
+ sts &= s->port.read_status_mask;
+ if (sts & MAX310X_LSR_RXBRK_BIT)
+ flag = TTY_BREAK;
+ else if (sts & MAX310X_LSR_RXPAR_BIT)
+ flag = TTY_PARITY;
+ else if (sts & MAX310X_LSR_FRERR_BIT)
+ flag = TTY_FRAME;
+ else if (sts & MAX310X_LSR_RXOVR_BIT)
+ flag = TTY_OVERRUN;
+ }
+
+ if (uart_handle_sysrq_char(s->port, ch))
+ continue;
+
+ if (sts & s->port.ignore_status_mask)
+ continue;
+
+ uart_insert_char(&s->port, sts, MAX310X_LSR_RXOVR_BIT,
+ ch, flag);
+ }
+
+ tty_flip_buffer_push(tty);
+
+ tty_kref_put(tty);
+}
+
+static void max310x_handle_tx(struct max310x_port *s)
+{
+ struct circ_buf *xmit = &s->port.state->xmit;
+ unsigned int txlen = 0, to_send;
+
+ if (unlikely(s->port.x_char)) {
+ regmap_write(s->regmap, MAX310X_THR_REG, s->port.x_char);
+ s->port.icount.tx++;
+ s->port.x_char = 0;
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port))
+ return;
+
+ /* Get length of data pending in circular buffer */
+ to_send = uart_circ_chars_pending(xmit);
+ if (likely(to_send)) {
+ /* Limit to size of TX FIFO */
+ regmap_read(s->regmap, MAX310X_TXFIFOLVL_REG, &txlen);
+ txlen = MAX310X_FIFO_SIZE - txlen;
+ to_send = (to_send > txlen) ? txlen : to_send;
+
+ dev_dbg(s->port.dev, "TX Len = %u\n", to_send);
+
+ /* Add data to send */
+ s->port.icount.tx += to_send;
+ while (to_send--) {
+ regmap_write(s->regmap, MAX310X_THR_REG,
+ xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ };
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&s->port);
+}
+
+static irqreturn_t max310x_ist(int irq, void *dev_id)
+{
+ struct max310x_port *s = (struct max310x_port *)dev_id;
+ unsigned int ists = 0, lsr = 0, rxlen = 0;
+
+ mutex_lock(&s->max310x_mutex);
+
+ for (;;) {
+ /* Read IRQ status & RX FIFO level */
+ regmap_read(s->regmap, MAX310X_IRQSTS_REG, &ists);
+ regmap_read(s->regmap, MAX310X_LSR_IRQSTS_REG, &lsr);
+ regmap_read(s->regmap, MAX310X_RXFIFOLVL_REG, &rxlen);
+ if (!ists && !(lsr & MAX310X_LSR_RXTO_BIT) && !rxlen)
+ break;
+
+ dev_dbg(s->port.dev, "IRQ status: 0x%02x\n", ists);
+
+ if (rxlen)
+ max310x_handle_rx(s, rxlen);
+ if (ists & MAX310X_IRQ_TX)
+ max310x_handle_tx(s);
+ if (ists & MAX310X_IRQ_CTS_BIT)
+ uart_handle_cts_change(&s->port,
+ !!(lsr & MAX310X_LSR_CTS_BIT));
+ }
+
+ mutex_unlock(&s->max310x_mutex);
+
+ return IRQ_HANDLED;
+}
+
+static void max310x_wq_proc(struct work_struct *ws)
+{
+ struct max310x_port *s = container_of(ws, struct max310x_port, tx_work);
+
+ mutex_lock(&s->max310x_mutex);
+ max310x_handle_tx(s);
+ mutex_unlock(&s->max310x_mutex);
+}
+
+static void max310x_start_tx(struct uart_port *port)
+{
+ struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+ queue_work(s->wq, &s->tx_work);
+}
+
+static void max310x_stop_tx(struct uart_port *port)
+{
+ /* Do nothing */
+}
+
+static void max310x_stop_rx(struct uart_port *port)
+{
+ /* Do nothing */
+}
+
+static unsigned int max310x_tx_empty(struct uart_port *port)
+{
+ unsigned int val = 0;
+ struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+ mutex_lock(&s->max310x_mutex);
+ regmap_read(s->regmap, MAX310X_TXFIFOLVL_REG, &val);
+ mutex_unlock(&s->max310x_mutex);
+
+ return val ? 0 : TIOCSER_TEMT;
+}
+
+static void max310x_enable_ms(struct uart_port *port)
+{
+ /* Modem status not supported */
+}
+
+static unsigned int max310x_get_mctrl(struct uart_port *port)
+{
+ /* DCD and DSR are not wired and CTS/RTS is handled automatically
+ * so just indicate DSR and CAR asserted
+ */
+ return TIOCM_DSR | TIOCM_CAR;
+}
+
+static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /* DCD and DSR are not wired and CTS/RTS is hadnled automatically
+ * so do nothing
+ */
+}
+
+static void max310x_break_ctl(struct uart_port *port, int break_state)
+{
+ struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+ mutex_lock(&s->max310x_mutex);
+ regmap_update_bits(s->regmap, MAX310X_LCR_REG,
+ MAX310X_LCR_TXBREAK_BIT,
+ break_state ? MAX310X_LCR_TXBREAK_BIT : 0);
+ mutex_unlock(&s->max310x_mutex);
+}
+
+static void max310x_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct max310x_port *s = container_of(port, struct max310x_port, port);
+ unsigned int lcr, flow = 0;
+ int baud;
+
+ mutex_lock(&s->max310x_mutex);
+
+ /* Mask termios capabilities we don't support */
+ termios->c_cflag &= ~CMSPAR;
+ termios->c_iflag &= ~IXANY;
+
+ /* Word size */
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ lcr = MAX310X_LCR_WORD_LEN_5;
+ break;
+ case CS6:
+ lcr = MAX310X_LCR_WORD_LEN_6;
+ break;
+ case CS7:
+ lcr = MAX310X_LCR_WORD_LEN_7;
+ break;
+ case CS8:
+ default:
+ lcr = MAX310X_LCR_WORD_LEN_8;
+ break;
+ }
+
+ /* Parity */
+ if (termios->c_cflag & PARENB) {
+ lcr |= MAX310X_LCR_PARITY_BIT;
+ if (!(termios->c_cflag & PARODD))
+ lcr |= MAX310X_LCR_EVENPARITY_BIT;
+ }
+
+ /* Stop bits */
+ if (termios->c_cflag & CSTOPB)
+ lcr |= MAX310X_LCR_STOPLEN_BIT; /* 2 stops */
+
+ /* Update LCR register */
+ regmap_write(s->regmap, MAX310X_LCR_REG, lcr);
+
+ /* Set read status mask */
+ port->read_status_mask = MAX310X_LSR_RXOVR_BIT;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= MAX310X_LSR_RXPAR_BIT |
+ MAX310X_LSR_FRERR_BIT;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= MAX310X_LSR_RXBRK_BIT;
+
+ /* Set status ignore mask */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNBRK)
+ port->ignore_status_mask |= MAX310X_LSR_RXBRK_BIT;
+ if (!(termios->c_cflag & CREAD))
+ port->ignore_status_mask |= MAX310X_LSR_RXPAR_BIT |
+ MAX310X_LSR_RXOVR_BIT |
+ MAX310X_LSR_FRERR_BIT |
+ MAX310X_LSR_RXBRK_BIT;
+
+ /* Configure flow control */
+ regmap_write(s->regmap, MAX310X_XON1_REG, termios->c_cc[VSTART]);
+ regmap_write(s->regmap, MAX310X_XOFF1_REG, termios->c_cc[VSTOP]);
+ if (termios->c_cflag & CRTSCTS)
+ flow |= MAX310X_FLOWCTRL_AUTOCTS_BIT |
+ MAX310X_FLOWCTRL_AUTORTS_BIT;
+ if (termios->c_iflag & IXON)
+ flow |= MAX310X_FLOWCTRL_SWFLOW3_BIT |
+ MAX310X_FLOWCTRL_SWFLOWEN_BIT;
+ if (termios->c_iflag & IXOFF)
+ flow |= MAX310X_FLOWCTRL_SWFLOW1_BIT |
+ MAX310X_FLOWCTRL_SWFLOWEN_BIT;
+ regmap_write(s->regmap, MAX310X_FLOWCTRL_REG, flow);
+
+ /* Get baud rate generator configuration */
+ baud = uart_get_baud_rate(port, termios, old,
+ port->uartclk / 16 / 0xffff,
+ port->uartclk / 4);
+
+ /* Setup baudrate generator */
+ max310x_set_baud(s, baud);
+
+ /* Update timeout according to new baud rate */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ mutex_unlock(&s->max310x_mutex);
+}
+
+static int max310x_startup(struct uart_port *port)
+{
+ unsigned int val, line = port->line;
+ struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+ if (s->pdata->suspend)
+ s->pdata->suspend(0);
+
+ mutex_lock(&s->max310x_mutex);
+
+ /* Configure baud rate, 9600 as default */
+ max310x_set_baud(s, 9600);
+
+ /* Configure LCR register, 8N1 mode by default */
+ val = MAX310X_LCR_WORD_LEN_8;
+ regmap_write(s->regmap, MAX310X_LCR_REG, val);
+
+ /* Configure MODE1 register */
+ regmap_update_bits(s->regmap, MAX310X_MODE1_REG,
+ MAX310X_MODE1_TRNSCVCTRL_BIT,
+ (s->pdata->uart_flags[line] & MAX310X_AUTO_DIR_CTRL)
+ ? MAX310X_MODE1_TRNSCVCTRL_BIT : 0);
+
+ /* Configure MODE2 register */
+ val = MAX310X_MODE2_RXEMPTINV_BIT;
+ if (s->pdata->uart_flags[line] & MAX310X_LOOPBACK)
+ val |= MAX310X_MODE2_LOOPBACK_BIT;
+ if (s->pdata->uart_flags[line] & MAX310X_ECHO_SUPRESS)
+ val |= MAX310X_MODE2_ECHOSUPR_BIT;
+
+ /* Reset FIFOs */
+ val |= MAX310X_MODE2_FIFORST_BIT;
+ regmap_write(s->regmap, MAX310X_MODE2_REG, val);
+
+ /* Configure FIFO trigger level register */
+ /* RX FIFO trigger for 16 words, TX FIFO trigger for 64 words */
+ val = MAX310X_FIFOTRIGLVL_RX(16) | MAX310X_FIFOTRIGLVL_TX(64);
+ regmap_write(s->regmap, MAX310X_FIFOTRIGLVL_REG, val);
+
+ /* Configure flow control levels */
+ /* Flow control halt level 96, resume level 48 */
+ val = MAX310X_FLOWLVL_RES(48) | MAX310X_FLOWLVL_HALT(96);
+ regmap_write(s->regmap, MAX310X_FLOWLVL_REG, val);
+
+ /* Clear timeout register */
+ regmap_write(s->regmap, MAX310X_RXTO_REG, 0);
+
+ /* Configure LSR interrupt enable register */
+ /* Enable RX timeout interrupt */
+ val = MAX310X_LSR_RXTO_BIT;
+ regmap_write(s->regmap, MAX310X_LSR_IRQEN_REG, val);
+
+ /* Clear FIFO reset */
+ regmap_update_bits(s->regmap, MAX310X_MODE2_REG,
+ MAX310X_MODE2_FIFORST_BIT, 0);
+
+ /* Clear IRQ status register by reading it */
+ regmap_read(s->regmap, MAX310X_IRQSTS_REG, &val);
+
+ /* Configure interrupt enable register */
+ /* Enable CTS change interrupt */
+ val = MAX310X_IRQ_CTS_BIT;
+ /* Enable RX, TX interrupts */
+ val |= MAX310X_IRQ_RX | MAX310X_IRQ_TX;
+ regmap_write(s->regmap, MAX310X_IRQEN_REG, val);
+
+ mutex_unlock(&s->max310x_mutex);
+
+ return 0;
+}
+
+static void max310x_shutdown(struct uart_port *port)
+{
+ struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+ /* Disable all interrupts */
+ mutex_lock(&s->max310x_mutex);
+ regmap_write(s->regmap, MAX310X_IRQEN_REG, 0);
+ mutex_unlock(&s->max310x_mutex);
+
+ if (s->pdata->suspend)
+ s->pdata->suspend(1);
+}
+
+static const char *max310x_type(struct uart_port *port)
+{
+ struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+ return (port->type == PORT_MAX310X) ? s->name : NULL;
+}
+
+static int max310x_request_port(struct uart_port *port)
+{
+ /* Do nothing */
+ return 0;
+}
+
+static void max310x_release_port(struct uart_port *port)
+{
+ /* Do nothing */
+}
+
+static void max310x_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE)
+ port->type = PORT_MAX310X;
+}
+
+static int max310x_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ if ((ser->type == PORT_UNKNOWN) || (ser->type == PORT_MAX310X))
+ return 0;
+ if (ser->irq == port->irq)
+ return 0;
+
+ return -EINVAL;
+}
+
+static struct uart_ops max310x_ops = {
+ .tx_empty = max310x_tx_empty,
+ .set_mctrl = max310x_set_mctrl,
+ .get_mctrl = max310x_get_mctrl,
+ .stop_tx = max310x_stop_tx,
+ .start_tx = max310x_start_tx,
+ .stop_rx = max310x_stop_rx,
+ .enable_ms = max310x_enable_ms,
+ .break_ctl = max310x_break_ctl,
+ .startup = max310x_startup,
+ .shutdown = max310x_shutdown,
+ .set_termios = max310x_set_termios,
+ .type = max310x_type,
+ .request_port = max310x_request_port,
+ .release_port = max310x_release_port,
+ .config_port = max310x_config_port,
+ .verify_port = max310x_verify_port,
+};
+
+static int max310x_suspend(struct spi_device *spi, pm_message_t state)
+{
+ int ret;
+ struct max310x_port *s = dev_get_drvdata(&spi->dev);
+
+ dev_dbg(&spi->dev, "Suspend\n");
+
+ ret = uart_suspend_port(&s->uart, &s->port);
+
+ mutex_lock(&s->max310x_mutex);
+
+ /* Enable sleep mode */
+ regmap_update_bits(s->regmap, MAX310X_MODE1_REG,
+ MAX310X_MODE1_FORCESLEEP_BIT,
+ MAX310X_MODE1_FORCESLEEP_BIT);
+
+ mutex_unlock(&s->max310x_mutex);
+
+ if (s->pdata->suspend)
+ s->pdata->suspend(1);
+
+ return ret;
+}
+
+static int max310x_resume(struct spi_device *spi)
+{
+ struct max310x_port *s = dev_get_drvdata(&spi->dev);
+
+ dev_dbg(&spi->dev, "Resume\n");
+
+ if (s->pdata->suspend)
+ s->pdata->suspend(0);
+
+ mutex_lock(&s->max310x_mutex);
+
+ /* Disable sleep mode */
+ regmap_update_bits(s->regmap, MAX310X_MODE1_REG,
+ MAX310X_MODE1_FORCESLEEP_BIT,
+ 0);
+
+ max310x_wait_pll(s);
+
+ mutex_unlock(&s->max310x_mutex);
+
+ return uart_resume_port(&s->uart, &s->port);
+}
+
+#ifdef CONFIG_GPIOLIB
+static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ unsigned int val = 0;
+ struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+
+ mutex_lock(&s->max310x_mutex);
+ regmap_read(s->regmap, MAX310X_GPIODATA_REG, &val);
+ mutex_unlock(&s->max310x_mutex);
+
+ return !!((val >> 4) & (1 << offset));
+}
+
+static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+
+ mutex_lock(&s->max310x_mutex);
+ regmap_update_bits(s->regmap, MAX310X_GPIODATA_REG, 1 << offset, value ?
+ 1 << offset : 0);
+ mutex_unlock(&s->max310x_mutex);
+}
+
+static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+
+ mutex_lock(&s->max310x_mutex);
+
+ regmap_update_bits(s->regmap, MAX310X_GPIOCFG_REG, 1 << offset, 0);
+
+ mutex_unlock(&s->max310x_mutex);
+
+ return 0;
+}
+
+static int max310x_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+
+ mutex_lock(&s->max310x_mutex);
+
+ regmap_update_bits(s->regmap, MAX310X_GPIOCFG_REG, 1 << offset,
+ 1 << offset);
+ regmap_update_bits(s->regmap, MAX310X_GPIODATA_REG, 1 << offset, value ?
+ 1 << offset : 0);
+
+ mutex_unlock(&s->max310x_mutex);
+
+ return 0;
+}
+#endif
+
+/* Generic platform data */
+static struct max310x_pdata generic_plat_data = {
+ .driver_flags = MAX310X_EXT_CLK,
+ .uart_flags[0] = MAX310X_ECHO_SUPRESS,
+ .frequency = 26000000,
+};
+
+static int __devinit max310x_probe(struct spi_device *spi)
+{
+ struct max310x_port *s;
+ struct device *dev = &spi->dev;
+ int chiptype = spi_get_device_id(spi)->driver_data;
+ struct max310x_pdata *pdata = dev->platform_data;
+ unsigned int val = 0;
+ int ret;
+
+ /* Check for IRQ */
+ if (spi->irq <= 0) {
+ dev_err(dev, "No IRQ specified\n");
+ return -ENOTSUPP;
+ }
+
+ /* Alloc port structure */
+ s = devm_kzalloc(dev, sizeof(struct max310x_port), GFP_KERNEL);
+ if (!s) {
+ dev_err(dev, "Error allocating port structure\n");
+ return -ENOMEM;
+ }
+ dev_set_drvdata(dev, s);
+
+ if (!pdata) {
+ dev_warn(dev, "No platform data supplied, using defaults\n");
+ pdata = &generic_plat_data;
+ }
+ s->pdata = pdata;
+
+ /* Individual chip settings */
+ switch (chiptype) {
+ case MAX310X_TYPE_MAX3107:
+ s->name = "MAX3107";
+ s->nr_gpio = 4;
+ s->uart.nr = 1;
+ s->regcfg.max_register = 0x1f;
+ break;
+ case MAX310X_TYPE_MAX3108:
+ s->name = "MAX3108";
+ s->nr_gpio = 4;
+ s->uart.nr = 1;
+ s->regcfg.max_register = 0x1e;
+ break;
+ default:
+ dev_err(dev, "Unsupported chip type %i\n", chiptype);
+ return -ENOTSUPP;
+ }
+
+ /* Check input frequency */
+ if ((pdata->driver_flags & MAX310X_EXT_CLK) &&
+ ((pdata->frequency < 500000) || (pdata->frequency > 35000000)))
+ goto err_freq;
+ /* Check frequency for quartz */
+ if (!(pdata->driver_flags & MAX310X_EXT_CLK) &&
+ ((pdata->frequency < 1000000) || (pdata->frequency > 4000000)))
+ goto err_freq;
+
+ mutex_init(&s->max310x_mutex);
+
+ /* Setup SPI bus */
+ spi->mode = SPI_MODE_0;
+ spi->bits_per_word = 8;
+ spi->max_speed_hz = 26000000;
+ spi_setup(spi);
+
+ /* Setup regmap */
+ s->regcfg.reg_bits = 8;
+ s->regcfg.val_bits = 8;
+ s->regcfg.read_flag_mask = 0x00;
+ s->regcfg.write_flag_mask = 0x80;
+ s->regcfg.cache_type = REGCACHE_RBTREE;
+ s->regcfg.writeable_reg = max3107_8_reg_writeable;
+ s->regcfg.volatile_reg = max310x_reg_volatile;
+ s->regcfg.precious_reg = max310x_reg_precious;
+ s->regmap = devm_regmap_init_spi(spi, &s->regcfg);
+ if (IS_ERR(s->regmap)) {
+ ret = PTR_ERR(s->regmap);
+ dev_err(dev, "Failed to initialize register map\n");
+ goto err_out;
+ }
+
+ /* Reset chip & check SPI function */
+ ret = regmap_write(s->regmap, MAX310X_MODE2_REG, MAX310X_MODE2_RST_BIT);
+ if (ret) {
+ dev_err(dev, "SPI transfer failed\n");
+ goto err_out;
+ }
+ /* Clear chip reset */
+ regmap_write(s->regmap, MAX310X_MODE2_REG, 0);
+
+ switch (chiptype) {
+ case MAX310X_TYPE_MAX3107:
+ /* Check REV ID to ensure we are talking to what we expect */
+ regmap_read(s->regmap, MAX3107_REVID_REG, &val);
+ if (((val & MAX3107_REV_MASK) != MAX3107_REV_ID)) {
+ dev_err(dev, "%s ID 0x%02x does not match\n",
+ s->name, val);
+ ret = -ENODEV;
+ goto err_out;
+ }
+ break;
+ case MAX310X_TYPE_MAX3108:
+ /* MAX3108 have not REV ID register, we just check default value
+ * from clocksource register to make sure everything works.
+ */
+ regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val);
+ if (val != (MAX310X_CLKSRC_EXTCLK_BIT |
+ MAX310X_CLKSRC_PLLBYP_BIT)) {
+ dev_err(dev, "%s not present\n", s->name);
+ ret = -ENODEV;
+ goto err_out;
+ }
+ break;
+ }
+
+ /* Board specific configure */
+ if (pdata->init)
+ pdata->init();
+ if (pdata->suspend)
+ pdata->suspend(0);
+
+ /* Calculate referecne clock */
+ s->uartclk = max310x_set_ref_clk(s);
+
+ /* Disable all interrupts */
+ regmap_write(s->regmap, MAX310X_IRQEN_REG, 0);
+
+ /* Setup MODE1 register */
+ val = MAX310X_MODE1_IRQSEL_BIT; /* Enable IRQ pin */
+ if (pdata->driver_flags & MAX310X_AUTOSLEEP)
+ val = MAX310X_MODE1_AUTOSLEEP_BIT;
+ regmap_write(s->regmap, MAX310X_MODE1_REG, val);
+
+ /* Setup interrupt */
+ ret = devm_request_threaded_irq(dev, spi->irq, NULL, max310x_ist,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ dev_name(dev), s);
+ if (ret) {
+ dev_err(dev, "Unable to reguest IRQ %i\n", spi->irq);
+ goto err_out;
+ }
+
+ /* Register UART driver */
+ s->uart.owner = THIS_MODULE;
+ s->uart.driver_name = dev_name(dev);
+ s->uart.dev_name = "ttyMAX";
+ s->uart.major = MAX310X_MAJOR;
+ s->uart.minor = MAX310X_MINOR;
+ ret = uart_register_driver(&s->uart);
+ if (ret) {
+ dev_err(dev, "Registering UART driver failed\n");
+ goto err_out;
+ }
+
+ /* Initialize workqueue for start TX */
+ s->wq = create_freezable_workqueue(dev_name(dev));
+ INIT_WORK(&s->tx_work, max310x_wq_proc);
+
+ /* Initialize UART port data */
+ s->port.line = 0;
+ s->port.dev = dev;
+ s->port.irq = spi->irq;
+ s->port.type = PORT_MAX310X;
+ s->port.fifosize = MAX310X_FIFO_SIZE;
+ s->port.flags = UPF_SKIP_TEST | UPF_FIXED_TYPE;
+ s->port.iotype = UPIO_PORT;
+ s->port.membase = (void __iomem *)0xffffffff; /* Bogus value */
+ s->port.uartclk = s->uartclk;
+ s->port.ops = &max310x_ops;
+ uart_add_one_port(&s->uart, &s->port);
+
+#ifdef CONFIG_GPIOLIB
+ /* Setup GPIO cotroller */
+ if (pdata->gpio_base) {
+ s->gpio.owner = THIS_MODULE;
+ s->gpio.dev = dev;
+ s->gpio.label = dev_name(dev);
+ s->gpio.direction_input = max310x_gpio_direction_input;
+ s->gpio.get = max310x_gpio_get;
+ s->gpio.direction_output= max310x_gpio_direction_output;
+ s->gpio.set = max310x_gpio_set;
+ s->gpio.base = pdata->gpio_base;
+ s->gpio.ngpio = s->nr_gpio;
+ if (gpiochip_add(&s->gpio)) {
+ /* Indicate that we should not call gpiochip_remove */
+ s->gpio.base = 0;
+ }
+ } else
+ dev_info(dev, "GPIO support not enabled\n");
+#endif
+
+ /* Go to suspend mode */
+ if (pdata->suspend)
+ pdata->suspend(1);
+
+ return 0;
+
+err_freq:
+ dev_err(dev, "Frequency parameter incorrect\n");
+ ret = -EINVAL;
+
+err_out:
+ dev_set_drvdata(dev, NULL);
+
+ return ret;
+}
+
+static int __devexit max310x_remove(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct max310x_port *s = dev_get_drvdata(dev);
+ int ret = 0;
+
+ dev_dbg(dev, "Removing port\n");
+
+ devm_free_irq(dev, s->port.irq, s);
+
+ destroy_workqueue(s->wq);
+
+ uart_remove_one_port(&s->uart, &s->port);
+
+ uart_unregister_driver(&s->uart);
+
+#ifdef CONFIG_GPIOLIB
+ if (s->pdata->gpio_base) {
+ ret = gpiochip_remove(&s->gpio);
+ if (ret)
+ dev_err(dev, "Failed to remove gpio chip: %d\n", ret);
+ }
+#endif
+
+ dev_set_drvdata(dev, NULL);
+
+ if (s->pdata->suspend)
+ s->pdata->suspend(1);
+ if (s->pdata->exit)
+ s->pdata->exit();
+
+ return ret;
+}
+
+static const struct spi_device_id max310x_id_table[] = {
+ { "max3107", MAX310X_TYPE_MAX3107 },
+ { "max3108", MAX310X_TYPE_MAX3108 },
+};
+MODULE_DEVICE_TABLE(spi, max310x_id_table);
+
+static struct spi_driver max310x_driver = {
+ .driver = {
+ .name = "max310x",
+ .owner = THIS_MODULE,
+ },
+ .probe = max310x_probe,
+ .remove = __devexit_p(max310x_remove),
+ .suspend = max310x_suspend,
+ .resume = max310x_resume,
+ .id_table = max310x_id_table,
+};
+module_spi_driver(max310x_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
+MODULE_DESCRIPTION("MAX310X serial driver");
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index bedac0d4c9ce..f19d04ed8586 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -775,11 +775,15 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
}
if (new->c_cflag & PARENB) {
+ if (new->c_cflag & CMSPAR)
+ mr1 |= MPC52xx_PSC_MODE_PARFORCE;
+
+ /* With CMSPAR, PARODD also means high parity (same as termios) */
mr1 |= (new->c_cflag & PARODD) ?
MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN;
- } else
+ } else {
mr1 |= MPC52xx_PSC_MODE_PARNONE;
-
+ }
mr2 = 0;
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 8131e2c28015..033e0bc9ebab 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -896,7 +896,7 @@ static int __init msm_serial_probe(struct platform_device *pdev)
return PTR_ERR(msm_port->clk);
if (msm_port->is_uartdm)
- clk_set_rate(msm_port->clk, 7372800);
+ clk_set_rate(msm_port->clk, 1843200);
port->uartclk = clk_get_rate(msm_port->clk);
printk(KERN_INFO "uartclk = %d\n", port->uartclk);
diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c
index b25e6ee71443..925d1fa153db 100644
--- a/drivers/tty/serial/msm_smd_tty.c
+++ b/drivers/tty/serial/msm_smd_tty.c
@@ -223,9 +223,11 @@ static int __init smd_tty_init(void)
return ret;
for (i = 0; i < smd_tty_channels_len; i++) {
- tty_port_init(&smd_tty[smd_tty_channels[i].id].port);
- smd_tty[smd_tty_channels[i].id].port.ops = &smd_tty_port_ops;
- tty_register_device(smd_tty_driver, smd_tty_channels[i].id, 0);
+ struct tty_port *port = &smd_tty[smd_tty_channels[i].id].port;
+ tty_port_init(port);
+ port->ops = &smd_tty_port_ops;
+ tty_port_register_device(port, smd_tty_driver,
+ smd_tty_channels[i].id, NULL);
}
return 0;
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 3a667eed63d6..6db3baa39a97 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -262,7 +262,7 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
ctrl &= ~AUART_CTRL2_RTSEN;
if (mctrl & TIOCM_RTS) {
- if (u->state->port.flags & ASYNC_CTS_FLOW)
+ if (tty_port_cts_enabled(&u->state->port))
ctrl |= AUART_CTRL2_RTSEN;
}
@@ -457,11 +457,11 @@ static void mxs_auart_shutdown(struct uart_port *u)
writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_CLR);
- writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET);
-
writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN,
u->membase + AUART_INTR_CLR);
+ writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET);
+
clk_disable_unprepare(s->clk);
}
@@ -781,6 +781,7 @@ out_free_irq:
auart_port[pdev->id] = NULL;
free_irq(s->irq, s);
out_free_clk:
+ put_device(s->dev);
clk_put(s->clk);
out_free:
kfree(s);
@@ -796,6 +797,7 @@ static int __devexit mxs_auart_remove(struct platform_device *pdev)
auart_port[pdev->id] = NULL;
+ put_device(s->dev);
clk_put(s->clk);
free_irq(s->irq, s);
kfree(s);
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 34e71874a892..df443b908ca3 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -105,6 +105,10 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
port->uartclk = clk;
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
| UPF_FIXED_PORT | UPF_FIXED_TYPE;
+
+ if (of_find_property(np, "no-loopback-test", NULL))
+ port->flags |= UPF_SKIP_TEST;
+
port->dev = &ofdev->dev;
if (type == PORT_TEGRA)
@@ -144,8 +148,15 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev)
switch (port_type) {
#ifdef CONFIG_SERIAL_8250
case PORT_8250 ... PORT_MAX_8250:
- ret = serial8250_register_port(&port);
+ {
+ /* For now the of bindings don't support the extra
+ 8250 specific bits */
+ struct uart_8250_port port8250;
+ memset(&port8250, 0, sizeof(port8250));
+ port8250.port = port;
+ ret = serial8250_register_8250_port(&port8250);
break;
+ }
#endif
#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
case PORT_NWPSERIAL:
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index d3cda0cb2df0..ccc2f35adff1 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -32,16 +32,16 @@
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
+#include <linux/platform_device.h>
#include <linux/io.h>
-#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <linux/serial_core.h>
#include <linux/irq.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
-#include <plat/dma.h>
-#include <plat/dmtimer.h>
#include <plat/omap-serial.h>
#define UART_BUILD_REVISION(x, y) (((x) << 8) | (y))
@@ -57,8 +57,8 @@
#define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK (1 << 7)
/* FCR register bitmasks */
-#define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT 6
#define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6)
+#define OMAP_UART_FCR_TX_FIFO_TRIG_MASK (0x3 << 4)
/* MVR register bitmasks */
#define OMAP_UART_MVR_SCHEME_SHIFT 30
@@ -71,12 +71,52 @@
#define OMAP_UART_MVR_MAJ_SHIFT 8
#define OMAP_UART_MVR_MIN_MASK 0x3f
+struct uart_omap_port {
+ struct uart_port port;
+ struct uart_omap_dma uart_dma;
+ struct device *dev;
+
+ unsigned char ier;
+ unsigned char lcr;
+ unsigned char mcr;
+ unsigned char fcr;
+ unsigned char efr;
+ unsigned char dll;
+ unsigned char dlh;
+ unsigned char mdr1;
+ unsigned char scr;
+
+ int use_dma;
+ /*
+ * Some bits in registers are cleared on a read, so they must
+ * be saved whenever the register is read but the bits will not
+ * be immediately processed.
+ */
+ unsigned int lsr_break_flag;
+ unsigned char msr_saved_flags;
+ char name[20];
+ unsigned long port_activity;
+ u32 context_loss_cnt;
+ u32 errata;
+ u8 wakeups_enabled;
+ unsigned int irq_pending:1;
+
+ int DTR_gpio;
+ int DTR_inverted;
+ int DTR_active;
+
+ struct pm_qos_request pm_qos_request;
+ u32 latency;
+ u32 calc_latency;
+ struct work_struct qos_work;
+ struct pinctrl *pins;
+};
+
+#define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port)))
+
static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
/* Forward declaration of functions */
-static void uart_tx_dma_callback(int lch, u16 ch_status, void *data);
-static void serial_omap_rxdma_poll(unsigned long uart_no);
-static int serial_omap_start_rxdma(struct uart_omap_port *up);
static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1);
static struct workqueue_struct *serial_omap_uart_wq;
@@ -101,6 +141,46 @@ static inline void serial_omap_clear_fifos(struct uart_omap_port *up)
serial_out(up, UART_FCR, 0);
}
+static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
+{
+ struct omap_uart_port_info *pdata = up->dev->platform_data;
+
+ if (!pdata || !pdata->get_context_loss_count)
+ return 0;
+
+ return pdata->get_context_loss_count(up->dev);
+}
+
+static void serial_omap_set_forceidle(struct uart_omap_port *up)
+{
+ struct omap_uart_port_info *pdata = up->dev->platform_data;
+
+ if (!pdata || !pdata->set_forceidle)
+ return;
+
+ pdata->set_forceidle(up->dev);
+}
+
+static void serial_omap_set_noidle(struct uart_omap_port *up)
+{
+ struct omap_uart_port_info *pdata = up->dev->platform_data;
+
+ if (!pdata || !pdata->set_noidle)
+ return;
+
+ pdata->set_noidle(up->dev);
+}
+
+static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
+{
+ struct omap_uart_port_info *pdata = up->dev->platform_data;
+
+ if (!pdata || !pdata->enable_wakeup)
+ return;
+
+ pdata->enable_wakeup(up->dev, enable);
+}
+
/*
* serial_omap_get_divisor - calculate divisor value
* @port: uart port info
@@ -126,151 +206,55 @@ serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
return port->uartclk/(baud * divisor);
}
-static void serial_omap_stop_rxdma(struct uart_omap_port *up)
-{
- if (up->uart_dma.rx_dma_used) {
- del_timer(&up->uart_dma.rx_timer);
- omap_stop_dma(up->uart_dma.rx_dma_channel);
- omap_free_dma(up->uart_dma.rx_dma_channel);
- up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
- up->uart_dma.rx_dma_used = false;
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
- }
-}
-
static void serial_omap_enable_ms(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->port.line);
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
up->ier |= UART_IER_MSI;
serial_out(up, UART_IER, up->ier);
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
}
static void serial_omap_stop_tx(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
- struct omap_uart_port_info *pdata = up->pdev->dev.platform_data;
-
- if (up->use_dma &&
- up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) {
- /*
- * Check if dma is still active. If yes do nothing,
- * return. Else stop dma
- */
- if (omap_get_dma_active_status(up->uart_dma.tx_dma_channel))
- return;
- omap_stop_dma(up->uart_dma.tx_dma_channel);
- omap_free_dma(up->uart_dma.tx_dma_channel);
- up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
- }
+ struct uart_omap_port *up = to_uart_omap_port(port);
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
if (up->ier & UART_IER_THRI) {
up->ier &= ~UART_IER_THRI;
serial_out(up, UART_IER, up->ier);
}
- if (!up->use_dma && pdata && pdata->set_forceidle)
- pdata->set_forceidle(up->pdev);
+ serial_omap_set_forceidle(up);
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
}
static void serial_omap_stop_rx(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
- pm_runtime_get_sync(&up->pdev->dev);
- if (up->use_dma)
- serial_omap_stop_rxdma(up);
+ pm_runtime_get_sync(up->dev);
up->ier &= ~UART_IER_RLSI;
up->port.read_status_mask &= ~UART_LSR_DR;
serial_out(up, UART_IER, up->ier);
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
-}
-
-static inline void receive_chars(struct uart_omap_port *up,
- unsigned int *status)
-{
- struct tty_struct *tty = up->port.state->port.tty;
- unsigned int flag, lsr = *status;
- unsigned char ch = 0;
- int max_count = 256;
-
- do {
- if (likely(lsr & UART_LSR_DR))
- ch = serial_in(up, UART_RX);
- flag = TTY_NORMAL;
- up->port.icount.rx++;
-
- if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
- /*
- * For statistics only
- */
- if (lsr & UART_LSR_BI) {
- lsr &= ~(UART_LSR_FE | UART_LSR_PE);
- up->port.icount.brk++;
- /*
- * We do the SysRQ and SAK checking
- * here because otherwise the break
- * may get masked by ignore_status_mask
- * or read_status_mask.
- */
- if (uart_handle_break(&up->port))
- goto ignore_char;
- } else if (lsr & UART_LSR_PE) {
- up->port.icount.parity++;
- } else if (lsr & UART_LSR_FE) {
- up->port.icount.frame++;
- }
-
- if (lsr & UART_LSR_OE)
- up->port.icount.overrun++;
-
- /*
- * Mask off conditions which should be ignored.
- */
- lsr &= up->port.read_status_mask;
-
-#ifdef CONFIG_SERIAL_OMAP_CONSOLE
- if (up->port.line == up->port.cons->index) {
- /* Recover the break flag from console xmit */
- lsr |= up->lsr_break_flag;
- }
-#endif
- if (lsr & UART_LSR_BI)
- flag = TTY_BREAK;
- else if (lsr & UART_LSR_PE)
- flag = TTY_PARITY;
- else if (lsr & UART_LSR_FE)
- flag = TTY_FRAME;
- }
-
- if (uart_handle_sysrq_char(&up->port, ch))
- goto ignore_char;
- uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
-ignore_char:
- lsr = serial_in(up, UART_LSR);
- } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
- spin_unlock(&up->port.lock);
- tty_flip_buffer_push(tty);
- spin_lock(&up->port.lock);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
}
-static void transmit_chars(struct uart_omap_port *up)
+static void transmit_chars(struct uart_omap_port *up, unsigned int lsr)
{
struct circ_buf *xmit = &up->port.state->xmit;
int count;
+ if (!(lsr & UART_LSR_THRE))
+ return;
+
if (up->port.x_char) {
serial_out(up, UART_TX, up->port.x_char);
up->port.icount.tx++;
@@ -290,8 +274,11 @@ static void transmit_chars(struct uart_omap_port *up)
break;
} while (--count > 0);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
+ spin_unlock(&up->port.lock);
uart_write_wakeup(&up->port);
+ spin_lock(&up->port.lock);
+ }
if (uart_circ_empty(xmit))
serial_omap_stop_tx(&up->port);
@@ -307,70 +294,13 @@ static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)
static void serial_omap_start_tx(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
- struct omap_uart_port_info *pdata = up->pdev->dev.platform_data;
- struct circ_buf *xmit;
- unsigned int start;
- int ret = 0;
-
- if (!up->use_dma) {
- pm_runtime_get_sync(&up->pdev->dev);
- serial_omap_enable_ier_thri(up);
- if (pdata && pdata->set_noidle)
- pdata->set_noidle(up->pdev);
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
- return;
- }
-
- if (up->uart_dma.tx_dma_used)
- return;
-
- xmit = &up->port.state->xmit;
-
- if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) {
- pm_runtime_get_sync(&up->pdev->dev);
- ret = omap_request_dma(up->uart_dma.uart_dma_tx,
- "UART Tx DMA",
- (void *)uart_tx_dma_callback, up,
- &(up->uart_dma.tx_dma_channel));
-
- if (ret < 0) {
- serial_omap_enable_ier_thri(up);
- return;
- }
- }
- spin_lock(&(up->uart_dma.tx_lock));
- up->uart_dma.tx_dma_used = true;
- spin_unlock(&(up->uart_dma.tx_lock));
+ struct uart_omap_port *up = to_uart_omap_port(port);
- start = up->uart_dma.tx_buf_dma_phys +
- (xmit->tail & (UART_XMIT_SIZE - 1));
-
- up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
- /*
- * It is a circular buffer. See if the buffer has wounded back.
- * If yes it will have to be transferred in two separate dma
- * transfers
- */
- if (start + up->uart_dma.tx_buf_size >=
- up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
- up->uart_dma.tx_buf_size =
- (up->uart_dma.tx_buf_dma_phys +
- UART_XMIT_SIZE) - start;
-
- omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
- OMAP_DMA_AMODE_CONSTANT,
- up->uart_dma.uart_base, 0, 0);
- omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
- OMAP_DMA_AMODE_POST_INC, start, 0, 0);
- omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
- OMAP_DMA_DATA_TYPE_S8,
- up->uart_dma.tx_buf_size, 1,
- OMAP_DMA_SYNC_ELEMENT,
- up->uart_dma.uart_dma_tx, 0);
- /* FIXME: Cache maintenance needed here? */
- omap_start_dma(up->uart_dma.tx_dma_channel);
+ pm_runtime_get_sync(up->dev);
+ serial_omap_enable_ier_thri(up);
+ serial_omap_set_noidle(up);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
}
static unsigned int check_modem_status(struct uart_omap_port *up)
@@ -401,76 +331,162 @@ static unsigned int check_modem_status(struct uart_omap_port *up)
return status;
}
+static void serial_omap_rlsi(struct uart_omap_port *up, unsigned int lsr)
+{
+ unsigned int flag;
+ unsigned char ch = 0;
+
+ if (likely(lsr & UART_LSR_DR))
+ ch = serial_in(up, UART_RX);
+
+ up->port.icount.rx++;
+ flag = TTY_NORMAL;
+
+ if (lsr & UART_LSR_BI) {
+ flag = TTY_BREAK;
+ lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+ up->port.icount.brk++;
+ /*
+ * We do the SysRQ and SAK checking
+ * here because otherwise the break
+ * may get masked by ignore_status_mask
+ * or read_status_mask.
+ */
+ if (uart_handle_break(&up->port))
+ return;
+
+ }
+
+ if (lsr & UART_LSR_PE) {
+ flag = TTY_PARITY;
+ up->port.icount.parity++;
+ }
+
+ if (lsr & UART_LSR_FE) {
+ flag = TTY_FRAME;
+ up->port.icount.frame++;
+ }
+
+ if (lsr & UART_LSR_OE)
+ up->port.icount.overrun++;
+
+#ifdef CONFIG_SERIAL_OMAP_CONSOLE
+ if (up->port.line == up->port.cons->index) {
+ /* Recover the break flag from console xmit */
+ lsr |= up->lsr_break_flag;
+ }
+#endif
+ uart_insert_char(&up->port, lsr, UART_LSR_OE, 0, flag);
+}
+
+static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr)
+{
+ unsigned char ch = 0;
+ unsigned int flag;
+
+ if (!(lsr & UART_LSR_DR))
+ return;
+
+ ch = serial_in(up, UART_RX);
+ flag = TTY_NORMAL;
+ up->port.icount.rx++;
+
+ if (uart_handle_sysrq_char(&up->port, ch))
+ return;
+
+ uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
+}
+
/**
* serial_omap_irq() - This handles the interrupt from one port
* @irq: uart port irq number
* @dev_id: uart port info
*/
-static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
+static irqreturn_t serial_omap_irq(int irq, void *dev_id)
{
struct uart_omap_port *up = dev_id;
+ struct tty_struct *tty = up->port.state->port.tty;
unsigned int iir, lsr;
- unsigned long flags;
+ unsigned int type;
+ irqreturn_t ret = IRQ_NONE;
+ int max_count = 256;
- pm_runtime_get_sync(&up->pdev->dev);
- iir = serial_in(up, UART_IIR);
- if (iir & UART_IIR_NO_INT) {
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
- return IRQ_NONE;
- }
+ spin_lock(&up->port.lock);
+ pm_runtime_get_sync(up->dev);
- spin_lock_irqsave(&up->port.lock, flags);
- lsr = serial_in(up, UART_LSR);
- if (iir & UART_IIR_RLSI) {
- if (!up->use_dma) {
- if (lsr & UART_LSR_DR)
- receive_chars(up, &lsr);
- } else {
- up->ier &= ~(UART_IER_RDI | UART_IER_RLSI);
- serial_out(up, UART_IER, up->ier);
- if ((serial_omap_start_rxdma(up) != 0) &&
- (lsr & UART_LSR_DR))
- receive_chars(up, &lsr);
+ do {
+ iir = serial_in(up, UART_IIR);
+ if (iir & UART_IIR_NO_INT)
+ break;
+
+ ret = IRQ_HANDLED;
+ lsr = serial_in(up, UART_LSR);
+
+ /* extract IRQ type from IIR register */
+ type = iir & 0x3e;
+
+ switch (type) {
+ case UART_IIR_MSI:
+ check_modem_status(up);
+ break;
+ case UART_IIR_THRI:
+ transmit_chars(up, lsr);
+ break;
+ case UART_IIR_RX_TIMEOUT:
+ /* FALLTHROUGH */
+ case UART_IIR_RDI:
+ serial_omap_rdi(up, lsr);
+ break;
+ case UART_IIR_RLSI:
+ serial_omap_rlsi(up, lsr);
+ break;
+ case UART_IIR_CTS_RTS_DSR:
+ /* simply try again */
+ break;
+ case UART_IIR_XOFF:
+ /* FALLTHROUGH */
+ default:
+ break;
}
- }
+ } while (!(iir & UART_IIR_NO_INT) && max_count--);
- check_modem_status(up);
- if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI))
- transmit_chars(up);
+ spin_unlock(&up->port.lock);
- spin_unlock_irqrestore(&up->port.lock, flags);
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
+ tty_flip_buffer_push(tty);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
up->port_activity = jiffies;
- return IRQ_HANDLED;
+
+ return ret;
}
static unsigned int serial_omap_tx_empty(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned long flags = 0;
unsigned int ret = 0;
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->port.line);
spin_lock_irqsave(&up->port.lock, flags);
ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
spin_unlock_irqrestore(&up->port.lock, flags);
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
return ret;
}
static unsigned int serial_omap_get_mctrl(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned int status;
unsigned int ret = 0;
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
status = check_modem_status(up);
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->port.line);
@@ -487,7 +503,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port)
static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned char mcr = 0;
dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->port.line);
@@ -502,20 +518,31 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (mctrl & TIOCM_LOOP)
mcr |= UART_MCR_LOOP;
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
up->mcr = serial_in(up, UART_MCR);
up->mcr |= mcr;
serial_out(up, UART_MCR, up->mcr);
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
+
+ if (gpio_is_valid(up->DTR_gpio) &&
+ !!(mctrl & TIOCM_DTR) != up->DTR_active) {
+ up->DTR_active = !up->DTR_active;
+ if (gpio_cansleep(up->DTR_gpio))
+ schedule_work(&up->qos_work);
+ else
+ gpio_set_value(up->DTR_gpio,
+ up->DTR_active != up->DTR_inverted);
+ }
}
static void serial_omap_break_ctl(struct uart_port *port, int break_state)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned long flags = 0;
dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->port.line);
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
spin_lock_irqsave(&up->port.lock, flags);
if (break_state == -1)
up->lcr |= UART_LCR_SBC;
@@ -523,12 +550,13 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)
up->lcr &= ~UART_LCR_SBC;
serial_out(up, UART_LCR, up->lcr);
spin_unlock_irqrestore(&up->port.lock, flags);
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
}
static int serial_omap_startup(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned long flags = 0;
int retval;
@@ -542,7 +570,7 @@ static int serial_omap_startup(struct uart_port *port)
dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line);
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
/*
* Clear the FIFO buffers and disable them.
* (they will be reenabled in set_termios())
@@ -573,20 +601,6 @@ static int serial_omap_startup(struct uart_port *port)
spin_unlock_irqrestore(&up->port.lock, flags);
up->msr_saved_flags = 0;
- if (up->use_dma) {
- free_page((unsigned long)up->port.state->xmit.buf);
- up->port.state->xmit.buf = dma_alloc_coherent(NULL,
- UART_XMIT_SIZE,
- (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys),
- 0);
- init_timer(&(up->uart_dma.rx_timer));
- up->uart_dma.rx_timer.function = serial_omap_rxdma_poll;
- up->uart_dma.rx_timer.data = up->port.line;
- /* Currently the buffer size is 4KB. Can increase it */
- up->uart_dma.rx_buf = dma_alloc_coherent(NULL,
- up->uart_dma.rx_buf_size,
- (dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0);
- }
/*
* Finally, enable interrupts. Note: Modem status interrupts
* are set via set_termios(), which will be occurring imminently
@@ -598,20 +612,20 @@ static int serial_omap_startup(struct uart_port *port)
/* Enable module level wake up */
serial_out(up, UART_OMAP_WER, OMAP_UART_WER_MOD_WKUP);
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
up->port_activity = jiffies;
return 0;
}
static void serial_omap_shutdown(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned long flags = 0;
dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->port.line);
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
/*
* Disable interrupts from this port
*/
@@ -634,19 +648,9 @@ static void serial_omap_shutdown(struct uart_port *port)
*/
if (serial_in(up, UART_LSR) & UART_LSR_DR)
(void) serial_in(up, UART_RX);
- if (up->use_dma) {
- dma_free_coherent(up->port.dev,
- UART_XMIT_SIZE, up->port.state->xmit.buf,
- up->uart_dma.tx_buf_dma_phys);
- up->port.state->xmit.buf = NULL;
- serial_omap_stop_rx(port);
- dma_free_coherent(up->port.dev,
- up->uart_dma.rx_buf_size, up->uart_dma.rx_buf,
- up->uart_dma.rx_buf_dma_phys);
- up->uart_dma.rx_buf = NULL;
- }
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
free_irq(up->port.irq, up);
}
@@ -667,19 +671,19 @@ serial_omap_configure_xonxoff
/*
* IXON Flag:
- * Enable XON/XOFF flow control on output.
- * Transmit XON1, XOFF1
+ * Flow control for OMAP.TX
+ * OMAP.RX should listen for XON/XOFF
*/
if (termios->c_iflag & IXON)
- up->efr |= OMAP_UART_SW_TX;
+ up->efr |= OMAP_UART_SW_RX;
/*
* IXOFF Flag:
- * Enable XON/XOFF flow control on input.
- * Receiver compares XON1, XOFF1.
+ * Flow control for OMAP.RX
+ * OMAP.TX should send XON/XOFF
*/
if (termios->c_iflag & IXOFF)
- up->efr |= OMAP_UART_SW_RX;
+ up->efr |= OMAP_UART_SW_TX;
serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
@@ -715,13 +719,16 @@ static void serial_omap_uart_qos_work(struct work_struct *work)
qos_work);
pm_qos_update_request(&up->pm_qos_request, up->latency);
+ if (gpio_is_valid(up->DTR_gpio))
+ gpio_set_value_cansleep(up->DTR_gpio,
+ up->DTR_active != up->DTR_inverted);
}
static void
serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned char cval = 0;
unsigned char efr = 0;
unsigned long flags = 0;
@@ -768,14 +775,12 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 |
UART_FCR_ENABLE_FIFO;
- if (up->use_dma)
- up->fcr |= UART_FCR_DMA_SELECT;
/*
* Ok, we're now changing the port state. Do it with
* interrupts disabled.
*/
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
spin_lock_irqsave(&up->port.lock, flags);
/*
@@ -845,14 +850,13 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
up->scr |= OMAP_UART_SCR_RX_TRIG_GRANU1_MASK;
- if (up->use_dma) {
- serial_out(up, UART_TI752_TLR, 0);
- up->scr |= UART_FCR_TRIGGER_4;
- } else {
- /* Set receive FIFO threshold to 1 byte */
- up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK;
- up->fcr |= (0x1 << OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT);
- }
+ /* Set receive FIFO threshold to 16 characters and
+ * transmit FIFO threshold to 16 spaces
+ */
+ up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK;
+ up->fcr &= ~OMAP_UART_FCR_TX_FIFO_TRIG_MASK;
+ up->fcr |= UART_FCR6_R_TRIGGER_16 | UART_FCR6_T_TRIGGER_24 |
+ UART_FCR_ENABLE_FIFO;
serial_out(up, UART_FCR, up->fcr);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
@@ -924,20 +928,30 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
serial_omap_configure_xonxoff(up, termios);
spin_unlock_irqrestore(&up->port.lock, flags);
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line);
}
+static int serial_omap_set_wake(struct uart_port *port, unsigned int state)
+{
+ struct uart_omap_port *up = to_uart_omap_port(port);
+
+ serial_omap_enable_wakeup(up, state);
+
+ return 0;
+}
+
static void
serial_omap_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned char efr;
dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->port.line);
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
efr = serial_in(up, UART_EFR);
serial_out(up, UART_EFR, efr | UART_EFR_ECB);
@@ -948,14 +962,15 @@ serial_omap_pm(struct uart_port *port, unsigned int state,
serial_out(up, UART_EFR, efr);
serial_out(up, UART_LCR, 0);
- if (!device_may_wakeup(&up->pdev->dev)) {
+ if (!device_may_wakeup(up->dev)) {
if (!state)
- pm_runtime_forbid(&up->pdev->dev);
+ pm_runtime_forbid(up->dev);
else
- pm_runtime_allow(&up->pdev->dev);
+ pm_runtime_allow(up->dev);
}
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
}
static void serial_omap_release_port(struct uart_port *port)
@@ -971,7 +986,7 @@ static int serial_omap_request_port(struct uart_port *port)
static void serial_omap_config_port(struct uart_port *port, int flags)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
dev_dbg(up->port.dev, "serial_omap_config_port+%d\n",
up->port.line);
@@ -989,7 +1004,7 @@ serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser)
static const char *
serial_omap_type(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
dev_dbg(up->port.dev, "serial_omap_type+%d\n", up->port.line);
return up->name;
@@ -1032,26 +1047,33 @@ static inline void wait_for_xmitr(struct uart_omap_port *up)
static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
wait_for_xmitr(up);
serial_out(up, UART_TX, ch);
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
}
static int serial_omap_poll_get_char(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned int status;
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
status = serial_in(up, UART_LSR);
- if (!(status & UART_LSR_DR))
- return NO_POLL_CHAR;
+ if (!(status & UART_LSR_DR)) {
+ status = NO_POLL_CHAR;
+ goto out;
+ }
status = serial_in(up, UART_RX);
- pm_runtime_put(&up->pdev->dev);
+
+out:
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
+
return status;
}
@@ -1065,7 +1087,7 @@ static struct uart_driver serial_omap_reg;
static void serial_omap_console_putchar(struct uart_port *port, int ch)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
wait_for_xmitr(up);
serial_out(up, UART_TX, ch);
@@ -1080,7 +1102,7 @@ serial_omap_console_write(struct console *co, const char *s,
unsigned int ier;
int locked = 1;
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
local_irq_save(flags);
if (up->port.sysrq)
@@ -1114,8 +1136,8 @@ serial_omap_console_write(struct console *co, const char *s,
if (up->msr_saved_flags)
check_modem_status(up);
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
if (locked)
spin_unlock(&up->port.lock);
local_irq_restore(flags);
@@ -1179,6 +1201,7 @@ static struct uart_ops serial_omap_pops = {
.shutdown = serial_omap_shutdown,
.set_termios = serial_omap_set_termios,
.pm = serial_omap_pm,
+ .set_wake = serial_omap_set_wake,
.type = serial_omap_type,
.release_port = serial_omap_release_port,
.request_port = serial_omap_request_port,
@@ -1203,10 +1226,8 @@ static int serial_omap_suspend(struct device *dev)
{
struct uart_omap_port *up = dev_get_drvdata(dev);
- if (up) {
- uart_suspend_port(&serial_omap_reg, &up->port);
- flush_work_sync(&up->qos_work);
- }
+ uart_suspend_port(&serial_omap_reg, &up->port);
+ flush_work_sync(&up->qos_work);
return 0;
}
@@ -1215,156 +1236,13 @@ static int serial_omap_resume(struct device *dev)
{
struct uart_omap_port *up = dev_get_drvdata(dev);
- if (up)
- uart_resume_port(&serial_omap_reg, &up->port);
+ uart_resume_port(&serial_omap_reg, &up->port);
+
return 0;
}
#endif
-static void serial_omap_rxdma_poll(unsigned long uart_no)
-{
- struct uart_omap_port *up = ui[uart_no];
- unsigned int curr_dma_pos, curr_transmitted_size;
- int ret = 0;
-
- curr_dma_pos = omap_get_dma_dst_pos(up->uart_dma.rx_dma_channel);
- if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) ||
- (curr_dma_pos == 0)) {
- if (jiffies_to_msecs(jiffies - up->port_activity) <
- up->uart_dma.rx_timeout) {
- mod_timer(&up->uart_dma.rx_timer, jiffies +
- usecs_to_jiffies(up->uart_dma.rx_poll_rate));
- } else {
- serial_omap_stop_rxdma(up);
- up->ier |= (UART_IER_RDI | UART_IER_RLSI);
- serial_out(up, UART_IER, up->ier);
- }
- return;
- }
-
- curr_transmitted_size = curr_dma_pos -
- up->uart_dma.prev_rx_dma_pos;
- up->port.icount.rx += curr_transmitted_size;
- tty_insert_flip_string(up->port.state->port.tty,
- up->uart_dma.rx_buf +
- (up->uart_dma.prev_rx_dma_pos -
- up->uart_dma.rx_buf_dma_phys),
- curr_transmitted_size);
- tty_flip_buffer_push(up->port.state->port.tty);
- up->uart_dma.prev_rx_dma_pos = curr_dma_pos;
- if (up->uart_dma.rx_buf_size +
- up->uart_dma.rx_buf_dma_phys == curr_dma_pos) {
- ret = serial_omap_start_rxdma(up);
- if (ret < 0) {
- serial_omap_stop_rxdma(up);
- up->ier |= (UART_IER_RDI | UART_IER_RLSI);
- serial_out(up, UART_IER, up->ier);
- }
- } else {
- mod_timer(&up->uart_dma.rx_timer, jiffies +
- usecs_to_jiffies(up->uart_dma.rx_poll_rate));
- }
- up->port_activity = jiffies;
-}
-
-static void uart_rx_dma_callback(int lch, u16 ch_status, void *data)
-{
- return;
-}
-
-static int serial_omap_start_rxdma(struct uart_omap_port *up)
-{
- int ret = 0;
-
- if (up->uart_dma.rx_dma_channel == -1) {
- pm_runtime_get_sync(&up->pdev->dev);
- ret = omap_request_dma(up->uart_dma.uart_dma_rx,
- "UART Rx DMA",
- (void *)uart_rx_dma_callback, up,
- &(up->uart_dma.rx_dma_channel));
- if (ret < 0)
- return ret;
-
- omap_set_dma_src_params(up->uart_dma.rx_dma_channel, 0,
- OMAP_DMA_AMODE_CONSTANT,
- up->uart_dma.uart_base, 0, 0);
- omap_set_dma_dest_params(up->uart_dma.rx_dma_channel, 0,
- OMAP_DMA_AMODE_POST_INC,
- up->uart_dma.rx_buf_dma_phys, 0, 0);
- omap_set_dma_transfer_params(up->uart_dma.rx_dma_channel,
- OMAP_DMA_DATA_TYPE_S8,
- up->uart_dma.rx_buf_size, 1,
- OMAP_DMA_SYNC_ELEMENT,
- up->uart_dma.uart_dma_rx, 0);
- }
- up->uart_dma.prev_rx_dma_pos = up->uart_dma.rx_buf_dma_phys;
- /* FIXME: Cache maintenance needed here? */
- omap_start_dma(up->uart_dma.rx_dma_channel);
- mod_timer(&up->uart_dma.rx_timer, jiffies +
- usecs_to_jiffies(up->uart_dma.rx_poll_rate));
- up->uart_dma.rx_dma_used = true;
- return ret;
-}
-
-static void serial_omap_continue_tx(struct uart_omap_port *up)
-{
- struct circ_buf *xmit = &up->port.state->xmit;
- unsigned int start = up->uart_dma.tx_buf_dma_phys
- + (xmit->tail & (UART_XMIT_SIZE - 1));
-
- if (uart_circ_empty(xmit))
- return;
-
- up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
- /*
- * It is a circular buffer. See if the buffer has wounded back.
- * If yes it will have to be transferred in two separate dma
- * transfers
- */
- if (start + up->uart_dma.tx_buf_size >=
- up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
- up->uart_dma.tx_buf_size =
- (up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start;
- omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
- OMAP_DMA_AMODE_CONSTANT,
- up->uart_dma.uart_base, 0, 0);
- omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
- OMAP_DMA_AMODE_POST_INC, start, 0, 0);
- omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
- OMAP_DMA_DATA_TYPE_S8,
- up->uart_dma.tx_buf_size, 1,
- OMAP_DMA_SYNC_ELEMENT,
- up->uart_dma.uart_dma_tx, 0);
- /* FIXME: Cache maintenance needed here? */
- omap_start_dma(up->uart_dma.tx_dma_channel);
-}
-
-static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
-{
- struct uart_omap_port *up = (struct uart_omap_port *)data;
- struct circ_buf *xmit = &up->port.state->xmit;
-
- xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & \
- (UART_XMIT_SIZE - 1);
- up->port.icount.tx += up->uart_dma.tx_buf_size;
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&up->port);
-
- if (uart_circ_empty(xmit)) {
- spin_lock(&(up->uart_dma.tx_lock));
- serial_omap_stop_tx(&up->port);
- up->uart_dma.tx_dma_used = false;
- spin_unlock(&(up->uart_dma.tx_lock));
- } else {
- omap_stop_dma(up->uart_dma.tx_dma_channel);
- serial_omap_continue_tx(up);
- }
- up->port_activity = jiffies;
- return;
-}
-
-static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
+static void __devinit omap_serial_fill_features_erratas(struct uart_omap_port *up)
{
u32 mvr, scheme;
u16 revision, major, minor;
@@ -1389,7 +1267,7 @@ static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
minor = (mvr & OMAP_UART_MVR_MIN_MASK);
break;
default:
- dev_warn(&up->pdev->dev,
+ dev_warn(up->dev,
"Unknown %s revision, defaulting to highest\n",
up->name);
/* highest possible revision */
@@ -1417,7 +1295,7 @@ static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
}
}
-static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
+static __devinit struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
{
struct omap_uart_port_info *omap_up_info;
@@ -1430,12 +1308,12 @@ static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
return omap_up_info;
}
-static int serial_omap_probe(struct platform_device *pdev)
+static int __devinit serial_omap_probe(struct platform_device *pdev)
{
struct uart_omap_port *up;
- struct resource *mem, *irq, *dma_tx, *dma_rx;
+ struct resource *mem, *irq;
struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
- int ret = -ENOSPC;
+ int ret;
if (pdev->dev.of_node)
omap_up_info = of_get_uart_port_info(&pdev->dev);
@@ -1458,19 +1336,30 @@ static int serial_omap_probe(struct platform_device *pdev)
return -EBUSY;
}
- dma_rx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
- if (!dma_rx)
- return -ENXIO;
-
- dma_tx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
- if (!dma_tx)
- return -ENXIO;
+ if (gpio_is_valid(omap_up_info->DTR_gpio) &&
+ omap_up_info->DTR_present) {
+ ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial");
+ if (ret < 0)
+ return ret;
+ ret = gpio_direction_output(omap_up_info->DTR_gpio,
+ omap_up_info->DTR_inverted);
+ if (ret < 0)
+ return ret;
+ }
up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL);
if (!up)
return -ENOMEM;
- up->pdev = pdev;
+ if (gpio_is_valid(omap_up_info->DTR_gpio) &&
+ omap_up_info->DTR_present) {
+ up->DTR_gpio = omap_up_info->DTR_gpio;
+ up->DTR_inverted = omap_up_info->DTR_inverted;
+ } else
+ up->DTR_gpio = -EINVAL;
+ up->DTR_active = 0;
+
+ up->dev = &pdev->dev;
up->port.dev = &pdev->dev;
up->port.type = PORT_OMAP;
up->port.iotype = UPIO_MEM;
@@ -1492,6 +1381,13 @@ static int serial_omap_probe(struct platform_device *pdev)
goto err_port_line;
}
+ up->pins = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(up->pins)) {
+ dev_warn(&pdev->dev, "did not get pins for uart%i error: %li\n",
+ up->port.line, PTR_ERR(up->pins));
+ up->pins = NULL;
+ }
+
sprintf(up->name, "OMAP UART%d", up->port.line);
up->port.mapbase = mem->start;
up->port.membase = devm_ioremap(&pdev->dev, mem->start,
@@ -1509,20 +1405,6 @@ static int serial_omap_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "No clock speed specified: using default:"
"%d\n", DEFAULT_CLK_SPEED);
}
- up->uart_dma.uart_base = mem->start;
-
- if (omap_up_info->dma_enabled) {
- up->uart_dma.uart_dma_tx = dma_tx->start;
- up->uart_dma.uart_dma_rx = dma_rx->start;
- up->use_dma = 1;
- up->uart_dma.rx_buf_size = omap_up_info->dma_rx_buf_size;
- up->uart_dma.rx_timeout = omap_up_info->dma_rx_timeout;
- up->uart_dma.rx_poll_rate = omap_up_info->dma_rx_poll_rate;
- spin_lock_init(&(up->uart_dma.tx_lock));
- spin_lock_init(&(up->uart_dma.rx_lock));
- up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
- up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
- }
up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
@@ -1531,12 +1413,13 @@ static int serial_omap_probe(struct platform_device *pdev)
serial_omap_uart_wq = create_singlethread_workqueue(up->name);
INIT_WORK(&up->qos_work, serial_omap_uart_qos_work);
+ platform_set_drvdata(pdev, up);
+ pm_runtime_enable(&pdev->dev);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev,
omap_up_info->autosuspend_timeout);
pm_runtime_irq_safe(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
omap_serial_fill_features_erratas(up);
@@ -1548,8 +1431,8 @@ static int serial_omap_probe(struct platform_device *pdev)
if (ret != 0)
goto err_add_port;
- pm_runtime_put(&pdev->dev);
- platform_set_drvdata(pdev, up);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
return 0;
err_add_port:
@@ -1562,17 +1445,15 @@ err_port_line:
return ret;
}
-static int serial_omap_remove(struct platform_device *dev)
+static int __devexit serial_omap_remove(struct platform_device *dev)
{
struct uart_omap_port *up = platform_get_drvdata(dev);
- if (up) {
- pm_runtime_disable(&up->pdev->dev);
- uart_remove_one_port(&serial_omap_reg, &up->port);
- pm_qos_remove_request(&up->pm_qos_request);
- }
+ pm_runtime_put_sync(up->dev);
+ pm_runtime_disable(up->dev);
+ uart_remove_one_port(&serial_omap_reg, &up->port);
+ pm_qos_remove_request(&up->pm_qos_request);
- platform_set_drvdata(dev, NULL);
return 0;
}
@@ -1602,7 +1483,7 @@ static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1)
timeout--;
if (!timeout) {
/* Should *never* happen. we warn and carry on */
- dev_crit(&up->pdev->dev, "Errata i202: timedout %x\n",
+ dev_crit(up->dev, "Errata i202: timedout %x\n",
serial_in(up, UART_LSR));
break;
}
@@ -1648,29 +1529,23 @@ static int serial_omap_runtime_suspend(struct device *dev)
if (!up)
return -EINVAL;
- if (!pdata || !pdata->enable_wakeup)
+ if (!pdata)
return 0;
- if (pdata->get_context_loss_count)
- up->context_loss_cnt = pdata->get_context_loss_count(dev);
+ up->context_loss_cnt = serial_omap_get_context_loss_count(up);
if (device_may_wakeup(dev)) {
if (!up->wakeups_enabled) {
- pdata->enable_wakeup(up->pdev, true);
+ serial_omap_enable_wakeup(up, true);
up->wakeups_enabled = true;
}
} else {
if (up->wakeups_enabled) {
- pdata->enable_wakeup(up->pdev, false);
+ serial_omap_enable_wakeup(up, false);
up->wakeups_enabled = false;
}
}
- /* Errata i291 */
- if (up->use_dma && pdata->set_forceidle &&
- (up->errata & UART_ERRATA_i291_DMA_FORCEIDLE))
- pdata->set_forceidle(up->pdev);
-
up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
schedule_work(&up->qos_work);
@@ -1680,24 +1555,14 @@ static int serial_omap_runtime_suspend(struct device *dev)
static int serial_omap_runtime_resume(struct device *dev)
{
struct uart_omap_port *up = dev_get_drvdata(dev);
- struct omap_uart_port_info *pdata = dev->platform_data;
-
- if (up && pdata) {
- if (pdata->get_context_loss_count) {
- u32 loss_cnt = pdata->get_context_loss_count(dev);
- if (up->context_loss_cnt != loss_cnt)
- serial_omap_restore_context(up);
- }
+ u32 loss_cnt = serial_omap_get_context_loss_count(up);
- /* Errata i291 */
- if (up->use_dma && pdata->set_noidle &&
- (up->errata & UART_ERRATA_i291_DMA_FORCEIDLE))
- pdata->set_noidle(up->pdev);
+ if (up->context_loss_cnt != loss_cnt)
+ serial_omap_restore_context(up);
- up->latency = up->calc_latency;
- schedule_work(&up->qos_work);
- }
+ up->latency = up->calc_latency;
+ schedule_work(&up->qos_work);
return 0;
}
@@ -1721,7 +1586,7 @@ MODULE_DEVICE_TABLE(of, omap_serial_of_match);
static struct platform_driver serial_omap_driver = {
.probe = serial_omap_probe,
- .remove = serial_omap_remove,
+ .remove = __devexit_p(serial_omap_remove),
.driver = {
.name = DRIVER_NAME,
.pm = &serial_omap_dev_pm_ops,
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 558ce8509a9a..4cd6c2381528 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -979,6 +979,10 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
priv->tx_dma_use = 1;
priv->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);
+ if (!priv->sg_tx_p) {
+ dev_err(priv->port.dev, "%s:kzalloc Failed\n", __func__);
+ return 0;
+ }
sg_init_table(priv->sg_tx_p, num); /* Initialize SG table */
sg = priv->sg_tx_p;
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 5847a4b855f7..9033fc6e0e4e 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -670,9 +670,19 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_pxa_port *up = serial_pxa_ports[co->index];
unsigned int ier;
+ unsigned long flags;
+ int locked = 1;
clk_prepare_enable(up->clk);
+ local_irq_save(flags);
+ if (up->port.sysrq)
+ locked = 0;
+ else if (oops_in_progress)
+ locked = spin_trylock(&up->port.lock);
+ else
+ spin_lock(&up->port.lock);
+
/*
* First save the IER then disable the interrupts
*/
@@ -688,6 +698,10 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
wait_for_xmitr(up);
serial_out(up, UART_IER, ier);
+ if (locked)
+ spin_unlock(&up->port.lock);
+ local_irq_restore(flags);
+
clk_disable_unprepare(up->clk);
}
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 02d07bfcfa8a..7f04717176aa 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -82,7 +82,7 @@ static inline const char *s3c24xx_serial_portname(struct uart_port *port)
static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
{
- return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
+ return rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE;
}
/*
@@ -268,7 +268,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
dbg("break!\n");
port->icount.brk++;
if (uart_handle_break(port))
- goto ignore_char;
+ goto ignore_char;
}
if (uerstat & S3C2410_UERSTAT_FRAME)
@@ -459,7 +459,7 @@ static int s3c24xx_serial_startup(struct uart_port *port)
s3c24xx_serial_portname(port), ourport);
if (ret != 0) {
- printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq);
+ dev_err(port->dev, "cannot get irq %d\n", ourport->rx_irq);
return ret;
}
@@ -473,7 +473,7 @@ static int s3c24xx_serial_startup(struct uart_port *port)
s3c24xx_serial_portname(port), ourport);
if (ret) {
- printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq);
+ dev_err(port->dev, "cannot get irq %d\n", ourport->tx_irq);
goto err;
}
@@ -502,7 +502,7 @@ static int s3c64xx_serial_startup(struct uart_port *port)
ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
s3c24xx_serial_portname(port), ourport);
if (ret) {
- printk(KERN_ERR "cannot get irq %d\n", port->irq);
+ dev_err(port->dev, "cannot get irq %d\n", port->irq);
return ret;
}
@@ -529,7 +529,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
switch (level) {
case 3:
- if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+ if (!IS_ERR(ourport->baudclk))
clk_disable(ourport->baudclk);
clk_disable(ourport->clk);
@@ -538,12 +538,12 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
case 0:
clk_enable(ourport->clk);
- if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+ if (!IS_ERR(ourport->baudclk))
clk_enable(ourport->baudclk);
break;
default:
- printk(KERN_ERR "s3c24xx_serial: unknown pm %d\n", level);
+ dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level);
}
}
@@ -604,7 +604,6 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
char clkname[MAX_CLK_NAME_LENGTH];
int calc_deviation, deviation = (1 << 30) - 1;
- *best_clk = NULL;
clk_sel = (ourport->cfg->clk_sel) ? ourport->cfg->clk_sel :
ourport->info->def_clk_sel;
for (cnt = 0; cnt < info->num_clks; cnt++) {
@@ -613,7 +612,7 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
sprintf(clkname, "clk_uart_baud%d", cnt);
clk = clk_get(ourport->port.dev, clkname);
- if (IS_ERR_OR_NULL(clk))
+ if (IS_ERR(clk))
continue;
rate = clk_get_rate(clk);
@@ -684,7 +683,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
{
struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
struct s3c24xx_uart_port *ourport = to_ourport(port);
- struct clk *clk = NULL;
+ struct clk *clk = ERR_PTR(-EINVAL);
unsigned long flags;
unsigned int baud, quot, clk_sel = 0;
unsigned int ulcon;
@@ -705,7 +704,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
quot = s3c24xx_serial_getclk(ourport, baud, &clk, &clk_sel);
if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
quot = port->custom_divisor;
- if (!clk)
+ if (IS_ERR(clk))
return;
/* check to see if we need to change clock source */
@@ -713,9 +712,9 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
if (ourport->baudclk != clk) {
s3c24xx_serial_setsource(port, clk_sel);
- if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
+ if (!IS_ERR(ourport->baudclk)) {
clk_disable(ourport->baudclk);
- ourport->baudclk = NULL;
+ ourport->baudclk = ERR_PTR(-EINVAL);
}
clk_enable(clk);
@@ -877,11 +876,24 @@ s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
static struct console s3c24xx_serial_console;
+static int __init s3c24xx_serial_console_init(void)
+{
+ register_console(&s3c24xx_serial_console);
+ return 0;
+}
+console_initcall(s3c24xx_serial_console_init);
+
#define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
#else
#define S3C24XX_SERIAL_CONSOLE NULL
#endif
+#ifdef CONFIG_CONSOLE_POLL
+static int s3c24xx_serial_get_poll_char(struct uart_port *port);
+static void s3c24xx_serial_put_poll_char(struct uart_port *port,
+ unsigned char c);
+#endif
+
static struct uart_ops s3c24xx_serial_ops = {
.pm = s3c24xx_serial_pm,
.tx_empty = s3c24xx_serial_tx_empty,
@@ -900,6 +912,10 @@ static struct uart_ops s3c24xx_serial_ops = {
.request_port = s3c24xx_serial_request_port,
.config_port = s3c24xx_serial_config_port,
.verify_port = s3c24xx_serial_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = s3c24xx_serial_get_poll_char,
+ .poll_put_char = s3c24xx_serial_put_poll_char,
+#endif
};
static struct uart_driver s3c24xx_uart_drv = {
@@ -1036,10 +1052,10 @@ static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
if (tty == NULL)
goto exit;
- termios = tty->termios;
+ termios = &tty->termios;
if (termios == NULL) {
- printk(KERN_WARNING "%s: no termios?\n", __func__);
+ dev_warn(uport->dev, "%s: no termios?\n", __func__);
goto exit;
}
@@ -1114,7 +1130,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
if (res == NULL) {
- printk(KERN_ERR "failed to find memory resource for uart\n");
+ dev_err(port->dev, "failed to find memory resource for uart\n");
return -EINVAL;
}
@@ -1130,7 +1146,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
ourport->rx_irq = ret;
ourport->tx_irq = ret + 1;
}
-
+
ret = platform_get_irq(platdev, 1);
if (ret > 0)
ourport->tx_irq = ret;
@@ -1160,7 +1176,11 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
struct uart_port *port = s3c24xx_dev_to_port(dev);
struct s3c24xx_uart_port *ourport = to_ourport(port);
- return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->baudclk->name);
+ if (IS_ERR(ourport->baudclk))
+ return -EINVAL;
+
+ return snprintf(buf, PAGE_SIZE, "* %s\n",
+ ourport->baudclk->name ?: "(null)");
}
static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
@@ -1200,6 +1220,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
return -ENODEV;
}
+ ourport->baudclk = ERR_PTR(-EINVAL);
ourport->info = ourport->drv_data->info;
ourport->cfg = (pdev->dev.platform_data) ?
(struct s3c2410_uartcfg *)pdev->dev.platform_data :
@@ -1312,6 +1333,36 @@ s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
}
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Console polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+static int s3c24xx_serial_get_poll_char(struct uart_port *port)
+{
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+ unsigned int ufstat;
+
+ ufstat = rd_regl(port, S3C2410_UFSTAT);
+ if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
+ return NO_POLL_CHAR;
+
+ return rd_regb(port, S3C2410_URXH);
+}
+
+static void s3c24xx_serial_put_poll_char(struct uart_port *port,
+ unsigned char c)
+{
+ unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
+
+ while (!s3c24xx_serial_console_txrdy(port, ufcon))
+ cpu_relax();
+ wr_regb(cons_uart, S3C2410_UTXH, c);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
static void
s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
{
@@ -1387,7 +1438,7 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
sprintf(clk_name, "clk_uart_baud%d", clk_sel);
clk = clk_get(port->dev, clk_name);
- if (!IS_ERR(clk) && clk != NULL)
+ if (!IS_ERR(clk))
rate = clk_get_rate(clk);
else
rate = 1;
@@ -1679,8 +1730,8 @@ static int __init s3c24xx_serial_modinit(void)
ret = uart_register_driver(&s3c24xx_uart_drv);
if (ret < 0) {
- printk(KERN_ERR "failed to register UART driver\n");
- return -1;
+ pr_err("Failed to register Samsung UART driver\n");
+ return ret;
}
return platform_driver_register(&samsung_serial_driver);
diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c
index e0b4b0a30a5a..9d664242b312 100644
--- a/drivers/tty/serial/sc26xx.c
+++ b/drivers/tty/serial/sc26xx.c
@@ -20,6 +20,10 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
+#include <linux/io.h>
+
+#warning "Please try migrate to use new driver SCCNXP and report the status" \
+ "in the linux-serial mailing list."
#if defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
new file mode 100644
index 000000000000..b7086d004f5f
--- /dev/null
+++ b/drivers/tty/serial/sccnxp.c
@@ -0,0 +1,990 @@
+/*
+ * NXP (Philips) SCC+++(SCN+++) serial driver
+ *
+ * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * Based on sc26xx.c, by Thomas Bogendörfer (tsbogend@alpha.franken.de)
+ *
+ * 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.
+ */
+
+#if defined(CONFIG_SERIAL_SCCNXP_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/console.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/sccnxp.h>
+
+#define SCCNXP_NAME "uart-sccnxp"
+#define SCCNXP_MAJOR 204
+#define SCCNXP_MINOR 205
+
+#define SCCNXP_MR_REG (0x00)
+# define MR0_BAUD_NORMAL (0 << 0)
+# define MR0_BAUD_EXT1 (1 << 0)
+# define MR0_BAUD_EXT2 (5 << 0)
+# define MR0_FIFO (1 << 3)
+# define MR0_TXLVL (1 << 4)
+# define MR1_BITS_5 (0 << 0)
+# define MR1_BITS_6 (1 << 0)
+# define MR1_BITS_7 (2 << 0)
+# define MR1_BITS_8 (3 << 0)
+# define MR1_PAR_EVN (0 << 2)
+# define MR1_PAR_ODD (1 << 2)
+# define MR1_PAR_NO (4 << 2)
+# define MR2_STOP1 (7 << 0)
+# define MR2_STOP2 (0xf << 0)
+#define SCCNXP_SR_REG (0x01)
+#define SCCNXP_CSR_REG SCCNXP_SR_REG
+# define SR_RXRDY (1 << 0)
+# define SR_FULL (1 << 1)
+# define SR_TXRDY (1 << 2)
+# define SR_TXEMT (1 << 3)
+# define SR_OVR (1 << 4)
+# define SR_PE (1 << 5)
+# define SR_FE (1 << 6)
+# define SR_BRK (1 << 7)
+#define SCCNXP_CR_REG (0x02)
+# define CR_RX_ENABLE (1 << 0)
+# define CR_RX_DISABLE (1 << 1)
+# define CR_TX_ENABLE (1 << 2)
+# define CR_TX_DISABLE (1 << 3)
+# define CR_CMD_MRPTR1 (0x01 << 4)
+# define CR_CMD_RX_RESET (0x02 << 4)
+# define CR_CMD_TX_RESET (0x03 << 4)
+# define CR_CMD_STATUS_RESET (0x04 << 4)
+# define CR_CMD_BREAK_RESET (0x05 << 4)
+# define CR_CMD_START_BREAK (0x06 << 4)
+# define CR_CMD_STOP_BREAK (0x07 << 4)
+# define CR_CMD_MRPTR0 (0x0b << 4)
+#define SCCNXP_RHR_REG (0x03)
+#define SCCNXP_THR_REG SCCNXP_RHR_REG
+#define SCCNXP_IPCR_REG (0x04)
+#define SCCNXP_ACR_REG SCCNXP_IPCR_REG
+# define ACR_BAUD0 (0 << 7)
+# define ACR_BAUD1 (1 << 7)
+# define ACR_TIMER_MODE (6 << 4)
+#define SCCNXP_ISR_REG (0x05)
+#define SCCNXP_IMR_REG SCCNXP_ISR_REG
+# define IMR_TXRDY (1 << 0)
+# define IMR_RXRDY (1 << 1)
+# define ISR_TXRDY(x) (1 << ((x * 4) + 0))
+# define ISR_RXRDY(x) (1 << ((x * 4) + 1))
+#define SCCNXP_IPR_REG (0x0d)
+#define SCCNXP_OPCR_REG SCCNXP_IPR_REG
+#define SCCNXP_SOP_REG (0x0e)
+#define SCCNXP_ROP_REG (0x0f)
+
+/* Route helpers */
+#define MCTRL_MASK(sig) (0xf << (sig))
+#define MCTRL_IBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_IP0)
+#define MCTRL_OBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_OP0)
+
+/* Supported chip types */
+enum {
+ SCCNXP_TYPE_SC2681 = 2681,
+ SCCNXP_TYPE_SC2691 = 2691,
+ SCCNXP_TYPE_SC2692 = 2692,
+ SCCNXP_TYPE_SC2891 = 2891,
+ SCCNXP_TYPE_SC2892 = 2892,
+ SCCNXP_TYPE_SC28202 = 28202,
+ SCCNXP_TYPE_SC68681 = 68681,
+ SCCNXP_TYPE_SC68692 = 68692,
+};
+
+struct sccnxp_port {
+ struct uart_driver uart;
+ struct uart_port port[SCCNXP_MAX_UARTS];
+
+ const char *name;
+ int irq;
+
+ u8 imr;
+ u8 addr_mask;
+ int freq_std;
+
+ int flags;
+#define SCCNXP_HAVE_IO 0x00000001
+#define SCCNXP_HAVE_MR0 0x00000002
+
+#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE
+ struct console console;
+#endif
+
+ struct mutex sccnxp_mutex;
+
+ struct sccnxp_pdata pdata;
+};
+
+static inline u8 sccnxp_raw_read(void __iomem *base, u8 reg, u8 shift)
+{
+ return readb(base + (reg << shift));
+}
+
+static inline void sccnxp_raw_write(void __iomem *base, u8 reg, u8 shift, u8 v)
+{
+ writeb(v, base + (reg << shift));
+}
+
+static inline u8 sccnxp_read(struct uart_port *port, u8 reg)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ return sccnxp_raw_read(port->membase, reg & s->addr_mask,
+ port->regshift);
+}
+
+static inline void sccnxp_write(struct uart_port *port, u8 reg, u8 v)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ sccnxp_raw_write(port->membase, reg & s->addr_mask, port->regshift, v);
+}
+
+static inline u8 sccnxp_port_read(struct uart_port *port, u8 reg)
+{
+ return sccnxp_read(port, (port->line << 3) + reg);
+}
+
+static inline void sccnxp_port_write(struct uart_port *port, u8 reg, u8 v)
+{
+ sccnxp_write(port, (port->line << 3) + reg, v);
+}
+
+static int sccnxp_update_best_err(int a, int b, int *besterr)
+{
+ int err = abs(a - b);
+
+ if ((*besterr < 0) || (*besterr > err)) {
+ *besterr = err;
+ return 0;
+ }
+
+ return 1;
+}
+
+struct baud_table {
+ u8 csr;
+ u8 acr;
+ u8 mr0;
+ int baud;
+};
+
+const struct baud_table baud_std[] = {
+ { 0, ACR_BAUD0, MR0_BAUD_NORMAL, 50, },
+ { 0, ACR_BAUD1, MR0_BAUD_NORMAL, 75, },
+ { 1, ACR_BAUD0, MR0_BAUD_NORMAL, 110, },
+ { 2, ACR_BAUD0, MR0_BAUD_NORMAL, 134, },
+ { 3, ACR_BAUD1, MR0_BAUD_NORMAL, 150, },
+ { 3, ACR_BAUD0, MR0_BAUD_NORMAL, 200, },
+ { 4, ACR_BAUD0, MR0_BAUD_NORMAL, 300, },
+ { 0, ACR_BAUD1, MR0_BAUD_EXT1, 450, },
+ { 1, ACR_BAUD0, MR0_BAUD_EXT2, 880, },
+ { 3, ACR_BAUD1, MR0_BAUD_EXT1, 900, },
+ { 5, ACR_BAUD0, MR0_BAUD_NORMAL, 600, },
+ { 7, ACR_BAUD0, MR0_BAUD_NORMAL, 1050, },
+ { 2, ACR_BAUD0, MR0_BAUD_EXT2, 1076, },
+ { 6, ACR_BAUD0, MR0_BAUD_NORMAL, 1200, },
+ { 10, ACR_BAUD1, MR0_BAUD_NORMAL, 1800, },
+ { 7, ACR_BAUD1, MR0_BAUD_NORMAL, 2000, },
+ { 8, ACR_BAUD0, MR0_BAUD_NORMAL, 2400, },
+ { 5, ACR_BAUD1, MR0_BAUD_EXT1, 3600, },
+ { 9, ACR_BAUD0, MR0_BAUD_NORMAL, 4800, },
+ { 10, ACR_BAUD0, MR0_BAUD_NORMAL, 7200, },
+ { 11, ACR_BAUD0, MR0_BAUD_NORMAL, 9600, },
+ { 8, ACR_BAUD0, MR0_BAUD_EXT1, 14400, },
+ { 12, ACR_BAUD1, MR0_BAUD_NORMAL, 19200, },
+ { 9, ACR_BAUD0, MR0_BAUD_EXT1, 28800, },
+ { 12, ACR_BAUD0, MR0_BAUD_NORMAL, 38400, },
+ { 11, ACR_BAUD0, MR0_BAUD_EXT1, 57600, },
+ { 12, ACR_BAUD1, MR0_BAUD_EXT1, 115200, },
+ { 12, ACR_BAUD0, MR0_BAUD_EXT1, 230400, },
+ { 0, 0, 0, 0 }
+};
+
+static int sccnxp_set_baud(struct uart_port *port, int baud)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+ int div_std, tmp_baud, bestbaud = baud, besterr = -1;
+ u8 i, acr = 0, csr = 0, mr0 = 0;
+
+ /* Find best baud from table */
+ for (i = 0; baud_std[i].baud && besterr; i++) {
+ if (baud_std[i].mr0 && !(s->flags & SCCNXP_HAVE_MR0))
+ continue;
+ div_std = DIV_ROUND_CLOSEST(s->freq_std, baud_std[i].baud);
+ tmp_baud = DIV_ROUND_CLOSEST(port->uartclk, div_std);
+ if (!sccnxp_update_best_err(baud, tmp_baud, &besterr)) {
+ acr = baud_std[i].acr;
+ csr = baud_std[i].csr;
+ mr0 = baud_std[i].mr0;
+ bestbaud = tmp_baud;
+ }
+ }
+
+ if (s->flags & SCCNXP_HAVE_MR0) {
+ /* Enable FIFO, set half level for TX */
+ mr0 |= MR0_FIFO | MR0_TXLVL;
+ /* Update MR0 */
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_MRPTR0);
+ sccnxp_port_write(port, SCCNXP_MR_REG, mr0);
+ }
+
+ sccnxp_port_write(port, SCCNXP_ACR_REG, acr | ACR_TIMER_MODE);
+ sccnxp_port_write(port, SCCNXP_CSR_REG, (csr << 4) | csr);
+
+ if (baud != bestbaud)
+ dev_dbg(port->dev, "Baudrate desired: %i, calculated: %i\n",
+ baud, bestbaud);
+
+ return bestbaud;
+}
+
+static void sccnxp_enable_irq(struct uart_port *port, int mask)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ s->imr |= mask << (port->line * 4);
+ sccnxp_write(port, SCCNXP_IMR_REG, s->imr);
+}
+
+static void sccnxp_disable_irq(struct uart_port *port, int mask)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ s->imr &= ~(mask << (port->line * 4));
+ sccnxp_write(port, SCCNXP_IMR_REG, s->imr);
+}
+
+static void sccnxp_set_bit(struct uart_port *port, int sig, int state)
+{
+ u8 bitmask;
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(sig)) {
+ bitmask = 1 << MCTRL_OBIT(s->pdata.mctrl_cfg[port->line], sig);
+ if (state)
+ sccnxp_write(port, SCCNXP_SOP_REG, bitmask);
+ else
+ sccnxp_write(port, SCCNXP_ROP_REG, bitmask);
+ }
+}
+
+static void sccnxp_handle_rx(struct uart_port *port)
+{
+ u8 sr;
+ unsigned int ch, flag;
+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+
+ if (!tty)
+ return;
+
+ for (;;) {
+ sr = sccnxp_port_read(port, SCCNXP_SR_REG);
+ if (!(sr & SR_RXRDY))
+ break;
+ sr &= SR_PE | SR_FE | SR_OVR | SR_BRK;
+
+ ch = sccnxp_port_read(port, SCCNXP_RHR_REG);
+
+ port->icount.rx++;
+ flag = TTY_NORMAL;
+
+ if (unlikely(sr)) {
+ if (sr & SR_BRK) {
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ } else if (sr & SR_PE)
+ port->icount.parity++;
+ else if (sr & SR_FE)
+ port->icount.frame++;
+ else if (sr & SR_OVR)
+ port->icount.overrun++;
+
+ sr &= port->read_status_mask;
+ if (sr & SR_BRK)
+ flag = TTY_BREAK;
+ else if (sr & SR_PE)
+ flag = TTY_PARITY;
+ else if (sr & SR_FE)
+ flag = TTY_FRAME;
+ else if (sr & SR_OVR)
+ flag = TTY_OVERRUN;
+ }
+
+ if (uart_handle_sysrq_char(port, ch))
+ continue;
+
+ if (sr & port->ignore_status_mask)
+ continue;
+
+ uart_insert_char(port, sr, SR_OVR, ch, flag);
+ }
+
+ tty_flip_buffer_push(tty);
+
+ tty_kref_put(tty);
+}
+
+static void sccnxp_handle_tx(struct uart_port *port)
+{
+ u8 sr;
+ struct circ_buf *xmit = &port->state->xmit;
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ if (unlikely(port->x_char)) {
+ sccnxp_port_write(port, SCCNXP_THR_REG, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ /* Disable TX if FIFO is empty */
+ if (sccnxp_port_read(port, SCCNXP_SR_REG) & SR_TXEMT) {
+ sccnxp_disable_irq(port, IMR_TXRDY);
+
+ /* Set direction to input */
+ if (s->flags & SCCNXP_HAVE_IO)
+ sccnxp_set_bit(port, DIR_OP, 0);
+ }
+ return;
+ }
+
+ while (!uart_circ_empty(xmit)) {
+ sr = sccnxp_port_read(port, SCCNXP_SR_REG);
+ if (!(sr & SR_TXRDY))
+ break;
+
+ sccnxp_port_write(port, SCCNXP_THR_REG, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+static irqreturn_t sccnxp_ist(int irq, void *dev_id)
+{
+ int i;
+ u8 isr;
+ struct sccnxp_port *s = (struct sccnxp_port *)dev_id;
+
+ mutex_lock(&s->sccnxp_mutex);
+
+ for (;;) {
+ isr = sccnxp_read(&s->port[0], SCCNXP_ISR_REG);
+ isr &= s->imr;
+ if (!isr)
+ break;
+
+ dev_dbg(s->port[0].dev, "IRQ status: 0x%02x\n", isr);
+
+ for (i = 0; i < s->uart.nr; i++) {
+ if (isr & ISR_RXRDY(i))
+ sccnxp_handle_rx(&s->port[i]);
+ if (isr & ISR_TXRDY(i))
+ sccnxp_handle_tx(&s->port[i]);
+ }
+ }
+
+ mutex_unlock(&s->sccnxp_mutex);
+
+ return IRQ_HANDLED;
+}
+
+static void sccnxp_start_tx(struct uart_port *port)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ mutex_lock(&s->sccnxp_mutex);
+
+ /* Set direction to output */
+ if (s->flags & SCCNXP_HAVE_IO)
+ sccnxp_set_bit(port, DIR_OP, 1);
+
+ sccnxp_enable_irq(port, IMR_TXRDY);
+
+ mutex_unlock(&s->sccnxp_mutex);
+}
+
+static void sccnxp_stop_tx(struct uart_port *port)
+{
+ /* Do nothing */
+}
+
+static void sccnxp_stop_rx(struct uart_port *port)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ mutex_lock(&s->sccnxp_mutex);
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE);
+ mutex_unlock(&s->sccnxp_mutex);
+}
+
+static unsigned int sccnxp_tx_empty(struct uart_port *port)
+{
+ u8 val;
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ mutex_lock(&s->sccnxp_mutex);
+ val = sccnxp_port_read(port, SCCNXP_SR_REG);
+ mutex_unlock(&s->sccnxp_mutex);
+
+ return (val & SR_TXEMT) ? TIOCSER_TEMT : 0;
+}
+
+static void sccnxp_enable_ms(struct uart_port *port)
+{
+ /* Do nothing */
+}
+
+static void sccnxp_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ if (!(s->flags & SCCNXP_HAVE_IO))
+ return;
+
+ mutex_lock(&s->sccnxp_mutex);
+
+ sccnxp_set_bit(port, DTR_OP, mctrl & TIOCM_DTR);
+ sccnxp_set_bit(port, RTS_OP, mctrl & TIOCM_RTS);
+
+ mutex_unlock(&s->sccnxp_mutex);
+}
+
+static unsigned int sccnxp_get_mctrl(struct uart_port *port)
+{
+ u8 bitmask, ipr;
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+ unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
+
+ if (!(s->flags & SCCNXP_HAVE_IO))
+ return mctrl;
+
+ mutex_lock(&s->sccnxp_mutex);
+
+ ipr = ~sccnxp_read(port, SCCNXP_IPCR_REG);
+
+ if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(DSR_IP)) {
+ bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line],
+ DSR_IP);
+ mctrl &= ~TIOCM_DSR;
+ mctrl |= (ipr & bitmask) ? TIOCM_DSR : 0;
+ }
+ if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(CTS_IP)) {
+ bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line],
+ CTS_IP);
+ mctrl &= ~TIOCM_CTS;
+ mctrl |= (ipr & bitmask) ? TIOCM_CTS : 0;
+ }
+ if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(DCD_IP)) {
+ bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line],
+ DCD_IP);
+ mctrl &= ~TIOCM_CAR;
+ mctrl |= (ipr & bitmask) ? TIOCM_CAR : 0;
+ }
+ if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(RNG_IP)) {
+ bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line],
+ RNG_IP);
+ mctrl &= ~TIOCM_RNG;
+ mctrl |= (ipr & bitmask) ? TIOCM_RNG : 0;
+ }
+
+ mutex_unlock(&s->sccnxp_mutex);
+
+ return mctrl;
+}
+
+static void sccnxp_break_ctl(struct uart_port *port, int break_state)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ mutex_lock(&s->sccnxp_mutex);
+ sccnxp_port_write(port, SCCNXP_CR_REG, break_state ?
+ CR_CMD_START_BREAK : CR_CMD_STOP_BREAK);
+ mutex_unlock(&s->sccnxp_mutex);
+}
+
+static void sccnxp_set_termios(struct uart_port *port,
+ struct ktermios *termios, struct ktermios *old)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+ u8 mr1, mr2;
+ int baud;
+
+ mutex_lock(&s->sccnxp_mutex);
+
+ /* Mask termios capabilities we don't support */
+ termios->c_cflag &= ~CMSPAR;
+
+ /* Disable RX & TX, reset break condition, status and FIFOs */
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_RX_RESET |
+ CR_RX_DISABLE | CR_TX_DISABLE);
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_TX_RESET);
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_STATUS_RESET);
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_BREAK_RESET);
+
+ /* Word size */
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ mr1 = MR1_BITS_5;
+ break;
+ case CS6:
+ mr1 = MR1_BITS_6;
+ break;
+ case CS7:
+ mr1 = MR1_BITS_7;
+ break;
+ case CS8:
+ default:
+ mr1 = MR1_BITS_8;
+ break;
+ }
+
+ /* Parity */
+ if (termios->c_cflag & PARENB) {
+ if (termios->c_cflag & PARODD)
+ mr1 |= MR1_PAR_ODD;
+ } else
+ mr1 |= MR1_PAR_NO;
+
+ /* Stop bits */
+ mr2 = (termios->c_cflag & CSTOPB) ? MR2_STOP2 : MR2_STOP1;
+
+ /* Update desired format */
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_MRPTR1);
+ sccnxp_port_write(port, SCCNXP_MR_REG, mr1);
+ sccnxp_port_write(port, SCCNXP_MR_REG, mr2);
+
+ /* Set read status mask */
+ port->read_status_mask = SR_OVR;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= SR_PE | SR_FE;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= SR_BRK;
+
+ /* Set status ignore mask */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNBRK)
+ port->ignore_status_mask |= SR_BRK;
+ if (!(termios->c_cflag & CREAD))
+ port->ignore_status_mask |= SR_PE | SR_OVR | SR_FE | SR_BRK;
+
+ /* Setup baudrate */
+ baud = uart_get_baud_rate(port, termios, old, 50,
+ (s->flags & SCCNXP_HAVE_MR0) ?
+ 230400 : 38400);
+ baud = sccnxp_set_baud(port, baud);
+
+ /* Update timeout according to new baud rate */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ if (tty_termios_baud_rate(termios))
+ tty_termios_encode_baud_rate(termios, baud, baud);
+
+ /* Enable RX & TX */
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE);
+
+ mutex_unlock(&s->sccnxp_mutex);
+}
+
+static int sccnxp_startup(struct uart_port *port)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ mutex_lock(&s->sccnxp_mutex);
+
+ if (s->flags & SCCNXP_HAVE_IO) {
+ /* Outputs are controlled manually */
+ sccnxp_write(port, SCCNXP_OPCR_REG, 0);
+ }
+
+ /* Reset break condition, status and FIFOs */
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_RX_RESET);
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_TX_RESET);
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_STATUS_RESET);
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_BREAK_RESET);
+
+ /* Enable RX & TX */
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE);
+
+ /* Enable RX interrupt */
+ sccnxp_enable_irq(port, IMR_RXRDY);
+
+ mutex_unlock(&s->sccnxp_mutex);
+
+ return 0;
+}
+
+static void sccnxp_shutdown(struct uart_port *port)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ mutex_lock(&s->sccnxp_mutex);
+
+ /* Disable interrupts */
+ sccnxp_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
+
+ /* Disable TX & RX */
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE | CR_TX_DISABLE);
+
+ /* Leave direction to input */
+ if (s->flags & SCCNXP_HAVE_IO)
+ sccnxp_set_bit(port, DIR_OP, 0);
+
+ mutex_unlock(&s->sccnxp_mutex);
+}
+
+static const char *sccnxp_type(struct uart_port *port)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ return (port->type == PORT_SC26XX) ? s->name : NULL;
+}
+
+static void sccnxp_release_port(struct uart_port *port)
+{
+ /* Do nothing */
+}
+
+static int sccnxp_request_port(struct uart_port *port)
+{
+ /* Do nothing */
+ return 0;
+}
+
+static void sccnxp_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE)
+ port->type = PORT_SC26XX;
+}
+
+static int sccnxp_verify_port(struct uart_port *port, struct serial_struct *s)
+{
+ if ((s->type == PORT_UNKNOWN) || (s->type == PORT_SC26XX))
+ return 0;
+ if (s->irq == port->irq)
+ return 0;
+
+ return -EINVAL;
+}
+
+static const struct uart_ops sccnxp_ops = {
+ .tx_empty = sccnxp_tx_empty,
+ .set_mctrl = sccnxp_set_mctrl,
+ .get_mctrl = sccnxp_get_mctrl,
+ .stop_tx = sccnxp_stop_tx,
+ .start_tx = sccnxp_start_tx,
+ .stop_rx = sccnxp_stop_rx,
+ .enable_ms = sccnxp_enable_ms,
+ .break_ctl = sccnxp_break_ctl,
+ .startup = sccnxp_startup,
+ .shutdown = sccnxp_shutdown,
+ .set_termios = sccnxp_set_termios,
+ .type = sccnxp_type,
+ .release_port = sccnxp_release_port,
+ .request_port = sccnxp_request_port,
+ .config_port = sccnxp_config_port,
+ .verify_port = sccnxp_verify_port,
+};
+
+#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE
+static void sccnxp_console_putchar(struct uart_port *port, int c)
+{
+ int tryes = 100000;
+
+ while (tryes--) {
+ if (sccnxp_port_read(port, SCCNXP_SR_REG) & SR_TXRDY) {
+ sccnxp_port_write(port, SCCNXP_THR_REG, c);
+ break;
+ }
+ barrier();
+ }
+}
+
+static void sccnxp_console_write(struct console *co, const char *c, unsigned n)
+{
+ struct sccnxp_port *s = (struct sccnxp_port *)co->data;
+ struct uart_port *port = &s->port[co->index];
+
+ mutex_lock(&s->sccnxp_mutex);
+ uart_console_write(port, c, n, sccnxp_console_putchar);
+ mutex_unlock(&s->sccnxp_mutex);
+}
+
+static int sccnxp_console_setup(struct console *co, char *options)
+{
+ struct sccnxp_port *s = (struct sccnxp_port *)co->data;
+ struct uart_port *port = &s->port[(co->index > 0) ? co->index : 0];
+ int baud = 9600, bits = 8, parity = 'n', flow = 'n';
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+#endif
+
+static int __devinit sccnxp_probe(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ int chiptype = pdev->id_entry->driver_data;
+ struct sccnxp_pdata *pdata = dev_get_platdata(&pdev->dev);
+ int i, ret, fifosize, freq_min, freq_max;
+ struct sccnxp_port *s;
+ void __iomem *membase;
+
+ if (!res) {
+ dev_err(&pdev->dev, "Missing memory resource data\n");
+ return -EADDRNOTAVAIL;
+ }
+
+ dev_set_name(&pdev->dev, SCCNXP_NAME);
+
+ s = devm_kzalloc(&pdev->dev, sizeof(struct sccnxp_port), GFP_KERNEL);
+ if (!s) {
+ dev_err(&pdev->dev, "Error allocating port structure\n");
+ return -ENOMEM;
+ }
+ platform_set_drvdata(pdev, s);
+
+ mutex_init(&s->sccnxp_mutex);
+
+ /* Individual chip settings */
+ switch (chiptype) {
+ case SCCNXP_TYPE_SC2681:
+ s->name = "SC2681";
+ s->uart.nr = 2;
+ s->freq_std = 3686400;
+ s->addr_mask = 0x0f;
+ s->flags = SCCNXP_HAVE_IO;
+ fifosize = 3;
+ freq_min = 1000000;
+ freq_max = 4000000;
+ break;
+ case SCCNXP_TYPE_SC2691:
+ s->name = "SC2691";
+ s->uart.nr = 1;
+ s->freq_std = 3686400;
+ s->addr_mask = 0x07;
+ s->flags = 0;
+ fifosize = 3;
+ freq_min = 1000000;
+ freq_max = 4000000;
+ break;
+ case SCCNXP_TYPE_SC2692:
+ s->name = "SC2692";
+ s->uart.nr = 2;
+ s->freq_std = 3686400;
+ s->addr_mask = 0x0f;
+ s->flags = SCCNXP_HAVE_IO;
+ fifosize = 3;
+ freq_min = 1000000;
+ freq_max = 4000000;
+ break;
+ case SCCNXP_TYPE_SC2891:
+ s->name = "SC2891";
+ s->uart.nr = 1;
+ s->freq_std = 3686400;
+ s->addr_mask = 0x0f;
+ s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0;
+ fifosize = 16;
+ freq_min = 100000;
+ freq_max = 8000000;
+ break;
+ case SCCNXP_TYPE_SC2892:
+ s->name = "SC2892";
+ s->uart.nr = 2;
+ s->freq_std = 3686400;
+ s->addr_mask = 0x0f;
+ s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0;
+ fifosize = 16;
+ freq_min = 100000;
+ freq_max = 8000000;
+ break;
+ case SCCNXP_TYPE_SC28202:
+ s->name = "SC28202";
+ s->uart.nr = 2;
+ s->freq_std = 14745600;
+ s->addr_mask = 0x7f;
+ s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0;
+ fifosize = 256;
+ freq_min = 1000000;
+ freq_max = 50000000;
+ break;
+ case SCCNXP_TYPE_SC68681:
+ s->name = "SC68681";
+ s->uart.nr = 2;
+ s->freq_std = 3686400;
+ s->addr_mask = 0x0f;
+ s->flags = SCCNXP_HAVE_IO;
+ fifosize = 3;
+ freq_min = 1000000;
+ freq_max = 4000000;
+ break;
+ case SCCNXP_TYPE_SC68692:
+ s->name = "SC68692";
+ s->uart.nr = 2;
+ s->freq_std = 3686400;
+ s->addr_mask = 0x0f;
+ s->flags = SCCNXP_HAVE_IO;
+ fifosize = 3;
+ freq_min = 1000000;
+ freq_max = 4000000;
+ break;
+ default:
+ dev_err(&pdev->dev, "Unsupported chip type %i\n", chiptype);
+ ret = -ENOTSUPP;
+ goto err_out;
+ }
+
+ if (!pdata) {
+ dev_warn(&pdev->dev,
+ "No platform data supplied, using defaults\n");
+ s->pdata.frequency = s->freq_std;
+ } else
+ memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata));
+
+ s->irq = platform_get_irq(pdev, 0);
+ if (s->irq <= 0) {
+ dev_err(&pdev->dev, "Missing irq resource data\n");
+ ret = -ENXIO;
+ goto err_out;
+ }
+
+ /* Check input frequency */
+ if ((s->pdata.frequency < freq_min) ||
+ (s->pdata.frequency > freq_max)) {
+ dev_err(&pdev->dev, "Frequency out of bounds\n");
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ membase = devm_request_and_ioremap(&pdev->dev, res);
+ if (!membase) {
+ dev_err(&pdev->dev, "Failed to ioremap\n");
+ ret = -EIO;
+ goto err_out;
+ }
+
+ s->uart.owner = THIS_MODULE;
+ s->uart.dev_name = "ttySC";
+ s->uart.major = SCCNXP_MAJOR;
+ s->uart.minor = SCCNXP_MINOR;
+#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE
+ s->uart.cons = &s->console;
+ s->uart.cons->device = uart_console_device;
+ s->uart.cons->write = sccnxp_console_write;
+ s->uart.cons->setup = sccnxp_console_setup;
+ s->uart.cons->flags = CON_PRINTBUFFER;
+ s->uart.cons->index = -1;
+ s->uart.cons->data = s;
+ strcpy(s->uart.cons->name, "ttySC");
+#endif
+ ret = uart_register_driver(&s->uart);
+ if (ret) {
+ dev_err(&pdev->dev, "Registering UART driver failed\n");
+ goto err_out;
+ }
+
+ for (i = 0; i < s->uart.nr; i++) {
+ s->port[i].line = i;
+ s->port[i].dev = &pdev->dev;
+ s->port[i].irq = s->irq;
+ s->port[i].type = PORT_SC26XX;
+ s->port[i].fifosize = fifosize;
+ s->port[i].flags = UPF_SKIP_TEST | UPF_FIXED_TYPE;
+ s->port[i].iotype = UPIO_MEM;
+ s->port[i].mapbase = res->start;
+ s->port[i].membase = membase;
+ s->port[i].regshift = s->pdata.reg_shift;
+ s->port[i].uartclk = s->pdata.frequency;
+ s->port[i].ops = &sccnxp_ops;
+ uart_add_one_port(&s->uart, &s->port[i]);
+ /* Set direction to input */
+ if (s->flags & SCCNXP_HAVE_IO)
+ sccnxp_set_bit(&s->port[i], DIR_OP, 0);
+ }
+
+ /* Disable interrupts */
+ s->imr = 0;
+ sccnxp_write(&s->port[0], SCCNXP_IMR_REG, 0);
+
+ /* Board specific configure */
+ if (s->pdata.init)
+ s->pdata.init();
+
+ ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL, sccnxp_ist,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ dev_name(&pdev->dev), s);
+ if (!ret)
+ return 0;
+
+ dev_err(&pdev->dev, "Unable to reguest IRQ %i\n", s->irq);
+
+err_out:
+ platform_set_drvdata(pdev, NULL);
+
+ return ret;
+}
+
+static int __devexit sccnxp_remove(struct platform_device *pdev)
+{
+ int i;
+ struct sccnxp_port *s = platform_get_drvdata(pdev);
+
+ devm_free_irq(&pdev->dev, s->irq, s);
+
+ for (i = 0; i < s->uart.nr; i++)
+ uart_remove_one_port(&s->uart, &s->port[i]);
+
+ uart_unregister_driver(&s->uart);
+ platform_set_drvdata(pdev, NULL);
+
+ if (s->pdata.exit)
+ s->pdata.exit();
+
+ return 0;
+}
+
+static const struct platform_device_id sccnxp_id_table[] = {
+ { "sc2681", SCCNXP_TYPE_SC2681 },
+ { "sc2691", SCCNXP_TYPE_SC2691 },
+ { "sc2692", SCCNXP_TYPE_SC2692 },
+ { "sc2891", SCCNXP_TYPE_SC2891 },
+ { "sc2892", SCCNXP_TYPE_SC2892 },
+ { "sc28202", SCCNXP_TYPE_SC28202 },
+ { "sc68681", SCCNXP_TYPE_SC68681 },
+ { "sc68692", SCCNXP_TYPE_SC68692 },
+};
+MODULE_DEVICE_TABLE(platform, sccnxp_id_table);
+
+static struct platform_driver sccnxp_uart_driver = {
+ .driver = {
+ .name = SCCNXP_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = sccnxp_probe,
+ .remove = __devexit_p(sccnxp_remove),
+ .id_table = sccnxp_id_table,
+};
+module_platform_driver(sccnxp_uart_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
+MODULE_DESCRIPTION("SCCNXP serial driver");
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index a21dc8e3b7c0..0fcfd98a9566 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -159,7 +159,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
retval = uport->ops->startup(uport);
if (retval == 0) {
if (uart_console(uport) && uport->cons->cflag) {
- tty->termios->c_cflag = uport->cons->cflag;
+ tty->termios.c_cflag = uport->cons->cflag;
uport->cons->cflag = 0;
}
/*
@@ -172,11 +172,11 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
* Setup the RTS and DTR signals once the
* port is open and ready to respond.
*/
- if (tty->termios->c_cflag & CBAUD)
+ if (tty->termios.c_cflag & CBAUD)
uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
}
- if (port->flags & ASYNC_CTS_FLOW) {
+ if (tty_port_cts_enabled(port)) {
spin_lock_irq(&uport->lock);
if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS))
tty->hw_stopped = 1;
@@ -240,7 +240,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
/*
* Turn off DTR and RTS early.
*/
- if (!tty || (tty->termios->c_cflag & HUPCL))
+ if (!tty || (tty->termios.c_cflag & HUPCL))
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
uart_port_shutdown(port);
@@ -440,10 +440,10 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
* If we have no tty, termios, or the port does not exist,
* then we can't set the parameters for this port.
*/
- if (!tty || !tty->termios || uport->type == PORT_UNKNOWN)
+ if (!tty || uport->type == PORT_UNKNOWN)
return;
- termios = tty->termios;
+ termios = &tty->termios;
/*
* Set flags based on termios cflag
@@ -614,7 +614,7 @@ static void uart_throttle(struct tty_struct *tty)
if (I_IXOFF(tty))
uart_send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
uart_clear_mctrl(state->uart_port, TIOCM_RTS);
}
@@ -630,42 +630,48 @@ static void uart_unthrottle(struct tty_struct *tty)
uart_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
uart_set_mctrl(port, TIOCM_RTS);
}
-static int uart_get_info(struct uart_state *state,
- struct serial_struct __user *retinfo)
+static void uart_get_info(struct tty_port *port,
+ struct uart_state *state,
+ struct serial_struct *retinfo)
{
struct uart_port *uport = state->uart_port;
- struct tty_port *port = &state->port;
- struct serial_struct tmp;
- memset(&tmp, 0, sizeof(tmp));
+ memset(retinfo, 0, sizeof(*retinfo));
- /* Ensure the state we copy is consistent and no hardware changes
- occur as we go */
- mutex_lock(&port->mutex);
-
- tmp.type = uport->type;
- tmp.line = uport->line;
- tmp.port = uport->iobase;
+ retinfo->type = uport->type;
+ retinfo->line = uport->line;
+ retinfo->port = uport->iobase;
if (HIGH_BITS_OFFSET)
- tmp.port_high = (long) uport->iobase >> HIGH_BITS_OFFSET;
- tmp.irq = uport->irq;
- tmp.flags = uport->flags;
- tmp.xmit_fifo_size = uport->fifosize;
- tmp.baud_base = uport->uartclk / 16;
- tmp.close_delay = jiffies_to_msecs(port->close_delay) / 10;
- tmp.closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ retinfo->port_high = (long) uport->iobase >> HIGH_BITS_OFFSET;
+ retinfo->irq = uport->irq;
+ retinfo->flags = uport->flags;
+ retinfo->xmit_fifo_size = uport->fifosize;
+ retinfo->baud_base = uport->uartclk / 16;
+ retinfo->close_delay = jiffies_to_msecs(port->close_delay) / 10;
+ retinfo->closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
ASYNC_CLOSING_WAIT_NONE :
jiffies_to_msecs(port->closing_wait) / 10;
- tmp.custom_divisor = uport->custom_divisor;
- tmp.hub6 = uport->hub6;
- tmp.io_type = uport->iotype;
- tmp.iomem_reg_shift = uport->regshift;
- tmp.iomem_base = (void *)(unsigned long)uport->mapbase;
+ retinfo->custom_divisor = uport->custom_divisor;
+ retinfo->hub6 = uport->hub6;
+ retinfo->io_type = uport->iotype;
+ retinfo->iomem_reg_shift = uport->regshift;
+ retinfo->iomem_base = (void *)(unsigned long)uport->mapbase;
+}
+
+static int uart_get_info_user(struct uart_state *state,
+ struct serial_struct __user *retinfo)
+{
+ struct tty_port *port = &state->port;
+ struct serial_struct tmp;
+ /* Ensure the state we copy is consistent and no hardware changes
+ occur as we go */
+ mutex_lock(&port->mutex);
+ uart_get_info(port, state, &tmp);
mutex_unlock(&port->mutex);
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
@@ -673,42 +679,30 @@ static int uart_get_info(struct uart_state *state,
return 0;
}
-static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
- struct serial_struct __user *newinfo)
+static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
+ struct uart_state *state,
+ struct serial_struct *new_info)
{
- struct serial_struct new_serial;
struct uart_port *uport = state->uart_port;
- struct tty_port *port = &state->port;
unsigned long new_port;
unsigned int change_irq, change_port, closing_wait;
unsigned int old_custom_divisor, close_delay;
upf_t old_flags, new_flags;
int retval = 0;
- if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
- return -EFAULT;
-
- new_port = new_serial.port;
+ new_port = new_info->port;
if (HIGH_BITS_OFFSET)
- new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
+ new_port += (unsigned long) new_info->port_high << HIGH_BITS_OFFSET;
- new_serial.irq = irq_canonicalize(new_serial.irq);
- close_delay = msecs_to_jiffies(new_serial.close_delay * 10);
- closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ new_info->irq = irq_canonicalize(new_info->irq);
+ close_delay = msecs_to_jiffies(new_info->close_delay * 10);
+ closing_wait = new_info->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
ASYNC_CLOSING_WAIT_NONE :
- msecs_to_jiffies(new_serial.closing_wait * 10);
+ msecs_to_jiffies(new_info->closing_wait * 10);
- /*
- * This semaphore protects port->count. It is also
- * very useful to prevent opens. Also, take the
- * port configuration semaphore to make sure that a
- * module insertion/removal doesn't change anything
- * under us.
- */
- mutex_lock(&port->mutex);
change_irq = !(uport->flags & UPF_FIXED_PORT)
- && new_serial.irq != uport->irq;
+ && new_info->irq != uport->irq;
/*
* Since changing the 'type' of the port changes its resource
@@ -717,29 +711,29 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
*/
change_port = !(uport->flags & UPF_FIXED_PORT)
&& (new_port != uport->iobase ||
- (unsigned long)new_serial.iomem_base != uport->mapbase ||
- new_serial.hub6 != uport->hub6 ||
- new_serial.io_type != uport->iotype ||
- new_serial.iomem_reg_shift != uport->regshift ||
- new_serial.type != uport->type);
+ (unsigned long)new_info->iomem_base != uport->mapbase ||
+ new_info->hub6 != uport->hub6 ||
+ new_info->io_type != uport->iotype ||
+ new_info->iomem_reg_shift != uport->regshift ||
+ new_info->type != uport->type);
old_flags = uport->flags;
- new_flags = new_serial.flags;
+ new_flags = new_info->flags;
old_custom_divisor = uport->custom_divisor;
if (!capable(CAP_SYS_ADMIN)) {
retval = -EPERM;
if (change_irq || change_port ||
- (new_serial.baud_base != uport->uartclk / 16) ||
+ (new_info->baud_base != uport->uartclk / 16) ||
(close_delay != port->close_delay) ||
(closing_wait != port->closing_wait) ||
- (new_serial.xmit_fifo_size &&
- new_serial.xmit_fifo_size != uport->fifosize) ||
+ (new_info->xmit_fifo_size &&
+ new_info->xmit_fifo_size != uport->fifosize) ||
(((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0))
goto exit;
uport->flags = ((uport->flags & ~UPF_USR_MASK) |
(new_flags & UPF_USR_MASK));
- uport->custom_divisor = new_serial.custom_divisor;
+ uport->custom_divisor = new_info->custom_divisor;
goto check_and_exit;
}
@@ -747,10 +741,10 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
* Ask the low level driver to verify the settings.
*/
if (uport->ops->verify_port)
- retval = uport->ops->verify_port(uport, &new_serial);
+ retval = uport->ops->verify_port(uport, new_info);
- if ((new_serial.irq >= nr_irqs) || (new_serial.irq < 0) ||
- (new_serial.baud_base < 9600))
+ if ((new_info->irq >= nr_irqs) || (new_info->irq < 0) ||
+ (new_info->baud_base < 9600))
retval = -EINVAL;
if (retval)
@@ -790,11 +784,11 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
uport->ops->release_port(uport);
uport->iobase = new_port;
- uport->type = new_serial.type;
- uport->hub6 = new_serial.hub6;
- uport->iotype = new_serial.io_type;
- uport->regshift = new_serial.iomem_reg_shift;
- uport->mapbase = (unsigned long)new_serial.iomem_base;
+ uport->type = new_info->type;
+ uport->hub6 = new_info->hub6;
+ uport->iotype = new_info->io_type;
+ uport->regshift = new_info->iomem_reg_shift;
+ uport->mapbase = (unsigned long)new_info->iomem_base;
/*
* Claim and map the new regions
@@ -835,16 +829,16 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
}
if (change_irq)
- uport->irq = new_serial.irq;
+ uport->irq = new_info->irq;
if (!(uport->flags & UPF_FIXED_PORT))
- uport->uartclk = new_serial.baud_base * 16;
+ uport->uartclk = new_info->baud_base * 16;
uport->flags = (uport->flags & ~UPF_CHANGE_MASK) |
(new_flags & UPF_CHANGE_MASK);
- uport->custom_divisor = new_serial.custom_divisor;
+ uport->custom_divisor = new_info->custom_divisor;
port->close_delay = close_delay;
port->closing_wait = closing_wait;
- if (new_serial.xmit_fifo_size)
- uport->fifosize = new_serial.xmit_fifo_size;
+ if (new_info->xmit_fifo_size)
+ uport->fifosize = new_info->xmit_fifo_size;
if (port->tty)
port->tty->low_latency =
(uport->flags & UPF_LOW_LATENCY) ? 1 : 0;
@@ -873,6 +867,28 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
} else
retval = uart_startup(tty, state, 1);
exit:
+ return retval;
+}
+
+static int uart_set_info_user(struct tty_struct *tty, struct uart_state *state,
+ struct serial_struct __user *newinfo)
+{
+ struct serial_struct new_serial;
+ struct tty_port *port = &state->port;
+ int retval;
+
+ if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
+ return -EFAULT;
+
+ /*
+ * This semaphore protects port->count. It is also
+ * very useful to prevent opens. Also, take the
+ * port configuration semaphore to make sure that a
+ * module insertion/removal doesn't change anything
+ * under us.
+ */
+ mutex_lock(&port->mutex);
+ retval = uart_set_info(tty, port, state, &new_serial);
mutex_unlock(&port->mutex);
return retval;
}
@@ -1115,11 +1131,11 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,
*/
switch (cmd) {
case TIOCGSERIAL:
- ret = uart_get_info(state, uarg);
+ ret = uart_get_info_user(state, uarg);
break;
case TIOCSSERIAL:
- ret = uart_set_info(tty, state, uarg);
+ ret = uart_set_info_user(tty, state, uarg);
break;
case TIOCSERCONFIG:
@@ -1187,7 +1203,7 @@ static void uart_set_ldisc(struct tty_struct *tty)
struct uart_port *uport = state->uart_port;
if (uport->ops->set_ldisc)
- uport->ops->set_ldisc(uport, tty->termios->c_line);
+ uport->ops->set_ldisc(uport, tty->termios.c_line);
}
static void uart_set_termios(struct tty_struct *tty,
@@ -1195,7 +1211,7 @@ static void uart_set_termios(struct tty_struct *tty,
{
struct uart_state *state = tty->driver_data;
unsigned long flags;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = tty->termios.c_cflag;
/*
@@ -1206,9 +1222,9 @@ static void uart_set_termios(struct tty_struct *tty,
*/
#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
if ((cflag ^ old_termios->c_cflag) == 0 &&
- tty->termios->c_ospeed == old_termios->c_ospeed &&
- tty->termios->c_ispeed == old_termios->c_ispeed &&
- RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) {
+ tty->termios.c_ospeed == old_termios->c_ospeed &&
+ tty->termios.c_ispeed == old_termios->c_ispeed &&
+ RELEVANT_IFLAG(tty->termios.c_iflag ^ old_termios->c_iflag) == 0) {
return;
}
@@ -1960,8 +1976,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
/*
* If that's unset, use the tty termios setting.
*/
- if (port->tty && port->tty->termios && termios.c_cflag == 0)
- termios = *(port->tty->termios);
+ if (port->tty && termios.c_cflag == 0)
+ termios = port->tty->termios;
if (console_suspend_enabled)
uart_change_pm(state, 0);
@@ -2113,6 +2129,7 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options)
int bits = 8;
int parity = 'n';
int flow = 'n';
+ int ret;
if (!state || !state->uart_port)
return -1;
@@ -2121,6 +2138,22 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options)
if (!(port->ops->poll_get_char && port->ops->poll_put_char))
return -1;
+ if (port->ops->poll_init) {
+ struct tty_port *tport = &state->port;
+
+ ret = 0;
+ mutex_lock(&tport->mutex);
+ /*
+ * We don't set ASYNCB_INITIALIZED as we only initialized the
+ * hw, e.g. state->xmit is still uninitialized.
+ */
+ if (!test_bit(ASYNCB_INITIALIZED, &tport->flags))
+ ret = port->ops->poll_init(port);
+ mutex_unlock(&tport->mutex);
+ if (ret)
+ return ret;
+ }
+
if (options) {
uart_parse_options(options, &baud, &parity, &bits, &flow);
return uart_set_options(port, NULL, baud, parity, bits, flow);
@@ -2293,6 +2326,36 @@ struct tty_driver *uart_console_device(struct console *co, int *index)
return p->tty_driver;
}
+static ssize_t uart_get_attr_uartclk(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct tty_port *port = dev_get_drvdata(dev);
+ struct uart_state *state = container_of(port, struct uart_state, port);
+
+ mutex_lock(&state->port.mutex);
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", state->uart_port->uartclk);
+ mutex_unlock(&state->port.mutex);
+
+ return ret;
+}
+
+static DEVICE_ATTR(uartclk, S_IRUSR | S_IRGRP, uart_get_attr_uartclk, NULL);
+
+static struct attribute *tty_dev_attrs[] = {
+ &dev_attr_uartclk.attr,
+ NULL,
+ };
+
+static const struct attribute_group tty_dev_attr_group = {
+ .attrs = tty_dev_attrs,
+ };
+
+static const struct attribute_group *tty_dev_attr_groups[] = {
+ &tty_dev_attr_group,
+ NULL
+ };
+
/**
* uart_add_one_port - attach a driver-defined port structure
* @drv: pointer to the uart low level driver structure for this port
@@ -2346,7 +2409,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
* Register the port whether it's detected or not. This allows
* setserial to be used to alter this ports parameters.
*/
- tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);
+ tty_dev = tty_port_register_device_attr(port, drv->tty_driver,
+ uport->line, uport->dev, port, tty_dev_attr_groups);
if (likely(!IS_ERR(tty_dev))) {
device_set_wakeup_capable(tty_dev, 1);
} else {
@@ -2454,9 +2518,12 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
{
struct uart_state *state = uport->state;
struct tty_port *port = &state->port;
- struct tty_ldisc *ld = tty_ldisc_ref(port->tty);
+ struct tty_ldisc *ld = NULL;
struct pps_event_time ts;
+ struct tty_struct *tty = port->tty;
+ if (tty)
+ ld = tty_ldisc_ref(tty);
if (ld && ld->ops->dcd_change)
pps_get_ts(&ts);
@@ -2469,12 +2536,12 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
if (port->flags & ASYNC_CHECK_CD) {
if (status)
wake_up_interruptible(&port->open_wait);
- else if (port->tty)
- tty_hangup(port->tty);
+ else if (tty)
+ tty_hangup(tty);
}
if (ld && ld->ops->dcd_change)
- ld->ops->dcd_change(port->tty, status, &ts);
+ ld->ops->dcd_change(tty, status, &ts);
if (ld)
tty_ldisc_deref(ld);
}
@@ -2492,7 +2559,7 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
uport->icount.cts++;
- if (port->flags & ASYNC_CTS_FLOW) {
+ if (tty_port_cts_enabled(port)) {
if (tty->hw_stopped) {
if (status) {
tty->hw_stopped = 0;
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index 5b3eda2024fe..a9e2bd1ab534 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -668,7 +668,7 @@ int sirfsoc_uart_probe(struct platform_device *pdev)
if (res == NULL) {
dev_err(&pdev->dev, "Insufficient resources.\n");
ret = -EFAULT;
- goto irq_err;
+ goto err;
}
port->irq = res->start;
@@ -676,7 +676,7 @@ int sirfsoc_uart_probe(struct platform_device *pdev)
sirfport->p = pinctrl_get_select_default(&pdev->dev);
ret = IS_ERR(sirfport->p);
if (ret)
- goto pin_err;
+ goto err;
}
port->ops = &sirfsoc_uart_ops;
@@ -695,9 +695,6 @@ port_err:
platform_set_drvdata(pdev, NULL);
if (sirfport->hw_flow_ctrl)
pinctrl_put(sirfport->p);
-pin_err:
-irq_err:
- devm_iounmap(&pdev->dev, port->membase);
err:
return ret;
}
@@ -709,7 +706,6 @@ static int sirfsoc_uart_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
if (sirfport->hw_flow_ctrl)
pinctrl_put(sirfport->p);
- devm_iounmap(&pdev->dev, port->membase);
uart_remove_one_port(&sirfsoc_uart_drv, port);
return 0;
}
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index 675303b8ed84..b97913dcdbff 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -58,10 +58,16 @@
enum su_type { SU_PORT_NONE, SU_PORT_MS, SU_PORT_KBD, SU_PORT_PORT };
static char *su_typev[] = { "su(???)", "su(mouse)", "su(kbd)", "su(serial)" };
+struct serial_uart_config {
+ char *name;
+ int dfl_xmit_fifo_size;
+ int flags;
+};
+
/*
* Here we define the default xmit fifo size used for each type of UART.
*/
-static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = {
+static const struct serial_uart_config uart_config[] = {
{ "unknown", 1, 0 },
{ "8250", 1, 0 },
{ "16450", 1, 0 },
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index 593d40ad0a6b..70e3a525bc82 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -1359,7 +1359,7 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info )
}
}
- if ( (info->port.flags & ASYNC_CTS_FLOW) &&
+ if (tty_port_cts_enabled(&info->port) &&
(status & MISCSTATUS_CTS_LATCHED) ) {
if (info->port.tty->hw_stopped) {
if (status & MISCSTATUS_CTS) {
@@ -1840,22 +1840,22 @@ static void shutdown(struct mgsl_struct * info)
usc_DisableInterrupts(info,RECEIVE_DATA + RECEIVE_STATUS +
TRANSMIT_DATA + TRANSMIT_STATUS + IO_PIN + MISC );
usc_DisableDmaInterrupts(info,DICR_MASTER + DICR_TRANSMIT + DICR_RECEIVE);
-
+
/* Disable DMAEN (Port 7, Bit 14) */
/* This disconnects the DMA request signal from the ISA bus */
/* on the ISA adapter. This has no effect for the PCI adapter */
usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) | BIT14));
-
+
/* Disable INTEN (Port 6, Bit12) */
/* This disconnects the IRQ request signal to the ISA bus */
/* on the ISA adapter. This has no effect for the PCI adapter */
usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) | BIT12));
-
- if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) {
+
+ if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) {
info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
usc_set_serial_signals(info);
}
-
+
spin_unlock_irqrestore(&info->irq_spinlock,flags);
mgsl_release_resources(info);
@@ -1895,7 +1895,7 @@ static void mgsl_program_hw(struct mgsl_struct *info)
usc_EnableInterrupts(info, IO_PIN);
usc_get_serial_signals(info);
- if (info->netcount || info->port.tty->termios->c_cflag & CREAD)
+ if (info->netcount || info->port.tty->termios.c_cflag & CREAD)
usc_start_receiver(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
@@ -1908,14 +1908,14 @@ static void mgsl_change_params(struct mgsl_struct *info)
unsigned cflag;
int bits_per_char;
- if (!info->port.tty || !info->port.tty->termios)
+ if (!info->port.tty)
return;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgsl_change_params(%s)\n",
__FILE__,__LINE__, info->device_name );
- cflag = info->port.tty->termios->c_cflag;
+ cflag = info->port.tty->termios.c_cflag;
/* if B0 rate (hangup) specified then negate DTR and RTS */
/* otherwise assert DTR and RTS */
@@ -2367,8 +2367,8 @@ static void mgsl_throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
mgsl_send_xchar(tty, STOP_CHAR(tty));
-
- if (tty->termios->c_cflag & CRTSCTS) {
+
+ if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->irq_spinlock,flags);
info->serial_signals &= ~SerialSignal_RTS;
usc_set_serial_signals(info);
@@ -2401,8 +2401,8 @@ static void mgsl_unthrottle(struct tty_struct * tty)
else
mgsl_send_xchar(tty, START_CHAR(tty));
}
-
- if (tty->termios->c_cflag & CRTSCTS) {
+
+ if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->irq_spinlock,flags);
info->serial_signals |= SerialSignal_RTS;
usc_set_serial_signals(info);
@@ -3045,7 +3045,7 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio
/* Handle transition to B0 status */
if (old_termios->c_cflag & CBAUD &&
- !(tty->termios->c_cflag & CBAUD)) {
+ !(tty->termios.c_cflag & CBAUD)) {
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
spin_lock_irqsave(&info->irq_spinlock,flags);
usc_set_serial_signals(info);
@@ -3054,9 +3054,9 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio
/* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) &&
- tty->termios->c_cflag & CBAUD) {
+ tty->termios.c_cflag & CBAUD) {
info->serial_signals |= SerialSignal_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
+ if (!(tty->termios.c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
info->serial_signals |= SerialSignal_RTS;
}
@@ -3067,7 +3067,7 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio
/* Handle turning off CRTSCTS */
if (old_termios->c_cflag & CRTSCTS &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
mgsl_start(tty);
}
@@ -3287,7 +3287,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
return 0;
}
- if (tty->termios->c_cflag & CLOCAL)
+ if (tty->termios.c_cflag & CLOCAL)
do_clocal = true;
/* Wait for carrier detect and the line to become
@@ -3313,7 +3313,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
port->blocked_open++;
while (1) {
- if (tty->termios->c_cflag & CBAUD)
+ if (tty->termios.c_cflag & CBAUD)
tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
@@ -3338,9 +3338,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
printk("%s(%d):block_til_ready blocking on %s count=%d\n",
__FILE__,__LINE__, tty->driver->name, port->count );
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
set_current_state(TASK_RUNNING);
@@ -3362,6 +3362,29 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
} /* end of block_til_ready() */
+static int mgsl_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ struct mgsl_struct *info;
+ int line = tty->index;
+
+ /* verify range of specified line number */
+ if (line >= mgsl_device_count) {
+ printk("%s(%d):mgsl_open with invalid line #%d.\n",
+ __FILE__, __LINE__, line);
+ return -ENODEV;
+ }
+
+ /* find the info structure for the specified line */
+ info = mgsl_device_list;
+ while (info && info->line != line)
+ info = info->next_device;
+ if (mgsl_paranoia_check(info, tty->name, "mgsl_open"))
+ return -ENODEV;
+ tty->driver_data = info;
+
+ return tty_port_install(&info->port, driver, tty);
+}
+
/* mgsl_open()
*
* Called when a port is opened. Init and enable port.
@@ -3374,26 +3397,10 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
*/
static int mgsl_open(struct tty_struct *tty, struct file * filp)
{
- struct mgsl_struct *info;
- int retval, line;
+ struct mgsl_struct *info = tty->driver_data;
unsigned long flags;
+ int retval;
- /* verify range of specified line number */
- line = tty->index;
- if (line >= mgsl_device_count) {
- printk("%s(%d):mgsl_open with invalid line #%d.\n",
- __FILE__,__LINE__,line);
- return -ENODEV;
- }
-
- /* find the info structure for the specified line */
- info = mgsl_device_list;
- while(info && info->line != line)
- info = info->next_device;
- if (mgsl_paranoia_check(info, tty->name, "mgsl_open"))
- return -ENODEV;
-
- tty->driver_data = info;
info->port.tty = tty;
if (debug_level >= DEBUG_LEVEL_INFO)
@@ -4297,6 +4304,7 @@ static struct mgsl_struct* mgsl_allocate_device(void)
} /* end of mgsl_allocate_device()*/
static const struct tty_operations mgsl_ops = {
+ .install = mgsl_install,
.open = mgsl_open,
.close = mgsl_close,
.write = mgsl_write,
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index aa1debf97cc7..b38e954eedd3 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -785,7 +785,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle transition to B0 status */
if (old_termios->c_cflag & CBAUD &&
- !(tty->termios->c_cflag & CBAUD)) {
+ !(tty->termios.c_cflag & CBAUD)) {
info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
spin_lock_irqsave(&info->lock,flags);
set_signals(info);
@@ -794,9 +794,9 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) &&
- tty->termios->c_cflag & CBAUD) {
+ tty->termios.c_cflag & CBAUD) {
info->signals |= SerialSignal_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
+ if (!(tty->termios.c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
info->signals |= SerialSignal_RTS;
}
@@ -807,7 +807,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle turning off CRTSCTS */
if (old_termios->c_cflag & CRTSCTS &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
tx_release(tty);
}
@@ -1372,7 +1372,7 @@ static void throttle(struct tty_struct * tty)
DBGINFO(("%s throttle\n", info->device_name));
if (I_IXOFF(tty))
send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->lock,flags);
info->signals &= ~SerialSignal_RTS;
set_signals(info);
@@ -1397,7 +1397,7 @@ static void unthrottle(struct tty_struct * tty)
else
send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->lock,flags);
info->signals |= SerialSignal_RTS;
set_signals(info);
@@ -2053,7 +2053,7 @@ static void cts_change(struct slgt_info *info, unsigned short status)
wake_up_interruptible(&info->event_wait_q);
info->pending_bh |= BH_STATUS;
- if (info->port.flags & ASYNC_CTS_FLOW) {
+ if (tty_port_cts_enabled(&info->port)) {
if (info->port.tty) {
if (info->port.tty->hw_stopped) {
if (info->signals & SerialSignal_CTS) {
@@ -2493,7 +2493,7 @@ static void shutdown(struct slgt_info *info)
slgt_irq_off(info, IRQ_ALL | IRQ_MASTER);
- if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) {
+ if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) {
info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
set_signals(info);
}
@@ -2534,7 +2534,7 @@ static void program_hw(struct slgt_info *info)
get_signals(info);
if (info->netcount ||
- (info->port.tty && info->port.tty->termios->c_cflag & CREAD))
+ (info->port.tty && info->port.tty->termios.c_cflag & CREAD))
rx_start(info);
spin_unlock_irqrestore(&info->lock,flags);
@@ -2548,11 +2548,11 @@ static void change_params(struct slgt_info *info)
unsigned cflag;
int bits_per_char;
- if (!info->port.tty || !info->port.tty->termios)
+ if (!info->port.tty)
return;
DBGINFO(("%s change_params\n", info->device_name));
- cflag = info->port.tty->termios->c_cflag;
+ cflag = info->port.tty->termios.c_cflag;
/* if B0 rate (hangup) specified then negate DTR and RTS */
/* otherwise assert DTR and RTS */
@@ -3292,7 +3292,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
return 0;
}
- if (tty->termios->c_cflag & CLOCAL)
+ if (tty->termios.c_cflag & CLOCAL)
do_clocal = true;
/* Wait for carrier detect and the line to become
@@ -3314,7 +3314,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
port->blocked_open++;
while (1) {
- if ((tty->termios->c_cflag & CBAUD))
+ if ((tty->termios.c_cflag & CBAUD))
tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
@@ -3336,9 +3336,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
}
DBGINFO(("%s block_til_ready wait\n", tty->driver->name));
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
set_current_state(TASK_RUNNING);
@@ -3689,8 +3689,11 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
}
}
- for (i=0; i < port_count; ++i)
- tty_register_device(serial_driver, port_array[i]->line, &(port_array[i]->pdev->dev));
+ for (i = 0; i < port_count; ++i) {
+ struct slgt_info *info = port_array[i];
+ tty_port_register_device(&info->port, serial_driver, info->line,
+ &info->pdev->dev);
+ }
}
static int __devinit init_one(struct pci_dev *dev,
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index a3dddc12d2fe..f17d9f3d84a2 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -711,15 +711,11 @@ static void ldisc_receive_buf(struct tty_struct *tty,
/* tty callbacks */
-/* Called when a port is opened. Init and enable port.
- */
-static int open(struct tty_struct *tty, struct file *filp)
+static int install(struct tty_driver *driver, struct tty_struct *tty)
{
SLMP_INFO *info;
- int retval, line;
- unsigned long flags;
+ int line = tty->index;
- line = tty->index;
if (line >= synclinkmp_device_count) {
printk("%s(%d): open with invalid line #%d.\n",
__FILE__,__LINE__,line);
@@ -727,17 +723,30 @@ static int open(struct tty_struct *tty, struct file *filp)
}
info = synclinkmp_device_list;
- while(info && info->line != line)
+ while (info && info->line != line)
info = info->next_device;
if (sanity_check(info, tty->name, "open"))
return -ENODEV;
- if ( info->init_error ) {
+ if (info->init_error) {
printk("%s(%d):%s device is not allocated, init error=%d\n",
- __FILE__,__LINE__,info->device_name,info->init_error);
+ __FILE__, __LINE__, info->device_name,
+ info->init_error);
return -ENODEV;
}
tty->driver_data = info;
+
+ return tty_port_install(&info->port, driver, tty);
+}
+
+/* Called when a port is opened. Init and enable port.
+ */
+static int open(struct tty_struct *tty, struct file *filp)
+{
+ SLMP_INFO *info = tty->driver_data;
+ unsigned long flags;
+ int retval;
+
info->port.tty = tty;
if (debug_level >= DEBUG_LEVEL_INFO)
@@ -873,7 +882,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle transition to B0 status */
if (old_termios->c_cflag & CBAUD &&
- !(tty->termios->c_cflag & CBAUD)) {
+ !(tty->termios.c_cflag & CBAUD)) {
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
spin_lock_irqsave(&info->lock,flags);
set_signals(info);
@@ -882,9 +891,9 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) &&
- tty->termios->c_cflag & CBAUD) {
+ tty->termios.c_cflag & CBAUD) {
info->serial_signals |= SerialSignal_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
+ if (!(tty->termios.c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
info->serial_signals |= SerialSignal_RTS;
}
@@ -895,7 +904,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle turning off CRTSCTS */
if (old_termios->c_cflag & CRTSCTS &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
tx_release(tty);
}
@@ -1473,7 +1482,7 @@ static void throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals &= ~SerialSignal_RTS;
set_signals(info);
@@ -1502,7 +1511,7 @@ static void unthrottle(struct tty_struct * tty)
send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals |= SerialSignal_RTS;
set_signals(info);
@@ -2491,7 +2500,7 @@ static void isr_io_pin( SLMP_INFO *info, u16 status )
}
}
- if ( (info->port.flags & ASYNC_CTS_FLOW) &&
+ if (tty_port_cts_enabled(&info->port) &&
(status & MISCSTATUS_CTS_LATCHED) ) {
if ( info->port.tty ) {
if (info->port.tty->hw_stopped) {
@@ -2708,7 +2717,7 @@ static void shutdown(SLMP_INFO * info)
reset_port(info);
- if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) {
+ if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) {
info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
set_signals(info);
}
@@ -2749,7 +2758,7 @@ static void program_hw(SLMP_INFO *info)
get_signals(info);
- if (info->netcount || (info->port.tty && info->port.tty->termios->c_cflag & CREAD) )
+ if (info->netcount || (info->port.tty && info->port.tty->termios.c_cflag & CREAD) )
rx_start(info);
spin_unlock_irqrestore(&info->lock,flags);
@@ -2762,14 +2771,14 @@ static void change_params(SLMP_INFO *info)
unsigned cflag;
int bits_per_char;
- if (!info->port.tty || !info->port.tty->termios)
+ if (!info->port.tty)
return;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s change_params()\n",
__FILE__,__LINE__, info->device_name );
- cflag = info->port.tty->termios->c_cflag;
+ cflag = info->port.tty->termios.c_cflag;
/* if B0 rate (hangup) specified then negate DTR and RTS */
/* otherwise assert DTR and RTS */
@@ -3306,7 +3315,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
return 0;
}
- if (tty->termios->c_cflag & CLOCAL)
+ if (tty->termios.c_cflag & CLOCAL)
do_clocal = true;
/* Wait for carrier detect and the line to become
@@ -3332,7 +3341,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
port->blocked_open++;
while (1) {
- if (tty->termios->c_cflag & CBAUD)
+ if (tty->termios.c_cflag & CBAUD)
tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
@@ -3357,9 +3366,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
printk("%s(%d):%s block_til_ready() count=%d\n",
__FILE__,__LINE__, tty->driver->name, port->count );
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
set_current_state(TASK_RUNNING);
@@ -3881,6 +3890,7 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
}
static const struct tty_operations ops = {
+ .install = install,
.open = open,
.close = close,
.write = write,
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index b425c79675ad..8a5a8b064616 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -181,10 +181,13 @@ struct tty_struct *alloc_tty_struct(void)
void free_tty_struct(struct tty_struct *tty)
{
+ if (!tty)
+ return;
if (tty->dev)
put_device(tty->dev);
kfree(tty->write_buf);
tty_buffer_free_all(tty);
+ tty->magic = 0xDEADDEAD;
kfree(tty);
}
@@ -573,7 +576,7 @@ void __tty_hangup(struct tty_struct *tty)
}
spin_unlock(&redirect_lock);
- tty_lock();
+ tty_lock(tty);
/* some functions below drop BTM, so we need this bit */
set_bit(TTY_HUPPING, &tty->flags);
@@ -666,7 +669,7 @@ void __tty_hangup(struct tty_struct *tty)
clear_bit(TTY_HUPPING, &tty->flags);
tty_ldisc_enable(tty);
- tty_unlock();
+ tty_unlock(tty);
if (f)
fput(f);
@@ -1103,12 +1106,12 @@ void tty_write_message(struct tty_struct *tty, char *msg)
{
if (tty) {
mutex_lock(&tty->atomic_write_lock);
- tty_lock();
+ tty_lock(tty);
if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
- tty_unlock();
+ tty_unlock(tty);
tty->ops->write(tty, msg, strlen(msg));
} else
- tty_unlock();
+ tty_unlock(tty);
tty_write_unlock(tty);
}
return;
@@ -1213,7 +1216,10 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)
*/
static void tty_line_name(struct tty_driver *driver, int index, char *p)
{
- sprintf(p, "%s%d", driver->name, index + driver->name_base);
+ if (driver->flags & TTY_DRIVER_UNNUMBERED_NODE)
+ strcpy(p, driver->name);
+ else
+ sprintf(p, "%s%d", driver->name, index + driver->name_base);
}
/**
@@ -1249,21 +1255,19 @@ int tty_init_termios(struct tty_struct *tty)
struct ktermios *tp;
int idx = tty->index;
- tp = tty->driver->termios[idx];
- if (tp == NULL) {
- tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
- if (tp == NULL)
- return -ENOMEM;
- memcpy(tp, &tty->driver->init_termios,
- sizeof(struct ktermios));
- tty->driver->termios[idx] = tp;
+ if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
+ tty->termios = tty->driver->init_termios;
+ else {
+ /* Check for lazy saved data */
+ tp = tty->driver->termios[idx];
+ if (tp != NULL)
+ tty->termios = *tp;
+ else
+ tty->termios = tty->driver->init_termios;
}
- tty->termios = tp;
- tty->termios_locked = tp + 1;
-
/* Compatibility until drivers always set this */
- tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
- tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+ tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios);
+ tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios);
return 0;
}
EXPORT_SYMBOL_GPL(tty_init_termios);
@@ -1403,10 +1407,18 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
}
initialize_tty_struct(tty, driver, idx);
+ tty_lock(tty);
retval = tty_driver_install_tty(driver, tty);
if (retval < 0)
goto err_deinit_tty;
+ if (!tty->port)
+ tty->port = driver->ports[idx];
+
+ WARN_RATELIMIT(!tty->port,
+ "%s: %s driver does not set tty->port. This will crash the kernel later. Fix the driver!\n",
+ __func__, tty->driver->name);
+
/*
* Structures all installed ... call the ldisc open routines.
* If we fail here just call release_tty to clean up. No need
@@ -1415,9 +1427,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
retval = tty_ldisc_setup(tty, tty->link);
if (retval)
goto err_release_tty;
+ /* Return the tty locked so that it cannot vanish under the caller */
return tty;
err_deinit_tty:
+ tty_unlock(tty);
deinitialize_tty_struct(tty);
free_tty_struct(tty);
err_module_put:
@@ -1426,6 +1440,7 @@ err_module_put:
/* call the tty release_tty routine to clean out this slot */
err_release_tty:
+ tty_unlock(tty);
printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, "
"clearing slot %d\n", idx);
release_tty(tty, idx);
@@ -1436,22 +1451,25 @@ void tty_free_termios(struct tty_struct *tty)
{
struct ktermios *tp;
int idx = tty->index;
- /* Kill this flag and push into drivers for locking etc */
- if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
- /* FIXME: Locking on ->termios array */
- tp = tty->termios;
- tty->driver->termios[idx] = NULL;
- kfree(tp);
+
+ /* If the port is going to reset then it has no termios to save */
+ if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
+ return;
+
+ /* Stash the termios data */
+ tp = tty->driver->termios[idx];
+ if (tp == NULL) {
+ tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
+ if (tp == NULL) {
+ pr_warn("tty: no memory to save termios state.\n");
+ return;
+ }
+ tty->driver->termios[idx] = tp;
}
+ *tp = tty->termios;
}
EXPORT_SYMBOL(tty_free_termios);
-void tty_shutdown(struct tty_struct *tty)
-{
- tty_driver_remove_tty(tty->driver, tty);
- tty_free_termios(tty);
-}
-EXPORT_SYMBOL(tty_shutdown);
/**
* release_one_tty - release tty structure memory
@@ -1462,7 +1480,6 @@ EXPORT_SYMBOL(tty_shutdown);
* in use. It also gets called when setup of a device fails.
*
* Locking:
- * tty_mutex - sometimes only
* takes the file list lock internally when working on the list
* of ttys that the driver keeps.
*
@@ -1495,11 +1512,6 @@ static void queue_release_one_tty(struct kref *kref)
{
struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
- if (tty->ops->shutdown)
- tty->ops->shutdown(tty);
- else
- tty_shutdown(tty);
-
/* The hangup queue is now free so we can reuse it rather than
waste a chunk of memory for each port */
INIT_WORK(&tty->hangup_work, release_one_tty);
@@ -1528,16 +1540,20 @@ EXPORT_SYMBOL(tty_kref_put);
* and decrement the refcount of the backing module.
*
* Locking:
- * tty_mutex - sometimes only
+ * tty_mutex
* takes the file list lock internally when working on the list
* of ttys that the driver keeps.
- * FIXME: should we require tty_mutex is held here ??
*
*/
static void release_tty(struct tty_struct *tty, int idx)
{
/* This should always be true but check for the moment */
WARN_ON(tty->index != idx);
+ WARN_ON(!mutex_is_locked(&tty_mutex));
+ if (tty->ops->shutdown)
+ tty->ops->shutdown(tty);
+ tty_free_termios(tty);
+ tty_driver_remove_tty(tty->driver, tty);
if (tty->link)
tty_kref_put(tty->link);
@@ -1572,22 +1588,12 @@ static int tty_release_checks(struct tty_struct *tty, struct tty_struct *o_tty,
__func__, idx, tty->name);
return -1;
}
- if (tty->termios != tty->driver->termios[idx]) {
- printk(KERN_DEBUG "%s: driver.termios[%d] not termios for (%s)\n",
- __func__, idx, tty->name);
- return -1;
- }
if (tty->driver->other) {
if (o_tty != tty->driver->other->ttys[idx]) {
printk(KERN_DEBUG "%s: other->table[%d] not o_tty for (%s)\n",
__func__, idx, tty->name);
return -1;
}
- if (o_tty->termios != tty->driver->other->termios[idx]) {
- printk(KERN_DEBUG "%s: other->termios[%d] not o_termios for (%s)\n",
- __func__, idx, tty->name);
- return -1;
- }
if (o_tty->link != tty) {
printk(KERN_DEBUG "%s: bad pty pointers\n", __func__);
return -1;
@@ -1628,7 +1634,7 @@ int tty_release(struct inode *inode, struct file *filp)
if (tty_paranoia_check(tty, inode, __func__))
return 0;
- tty_lock();
+ tty_lock(tty);
check_tty_count(tty, __func__);
__tty_fasync(-1, filp, 0);
@@ -1637,10 +1643,11 @@ int tty_release(struct inode *inode, struct file *filp)
pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER);
devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
+ /* Review: parallel close */
o_tty = tty->link;
if (tty_release_checks(tty, o_tty, idx)) {
- tty_unlock();
+ tty_unlock(tty);
return 0;
}
@@ -1652,7 +1659,7 @@ int tty_release(struct inode *inode, struct file *filp)
if (tty->ops->close)
tty->ops->close(tty, filp);
- tty_unlock();
+ tty_unlock(tty);
/*
* Sanity check: if tty->count is going to zero, there shouldn't be
* any waiters on tty->read_wait or tty->write_wait. We test the
@@ -1675,7 +1682,7 @@ int tty_release(struct inode *inode, struct file *filp)
opens on /dev/tty */
mutex_lock(&tty_mutex);
- tty_lock();
+ tty_lock_pair(tty, o_tty);
tty_closing = tty->count <= 1;
o_tty_closing = o_tty &&
(o_tty->count <= (pty_master ? 1 : 0));
@@ -1706,7 +1713,7 @@ int tty_release(struct inode *inode, struct file *filp)
printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
__func__, tty_name(tty, buf));
- tty_unlock();
+ tty_unlock_pair(tty, o_tty);
mutex_unlock(&tty_mutex);
schedule();
}
@@ -1715,6 +1722,9 @@ int tty_release(struct inode *inode, struct file *filp)
* The closing flags are now consistent with the open counts on
* both sides, and we've completed the last operation that could
* block, so it's safe to proceed with closing.
+ *
+ * We must *not* drop the tty_mutex until we ensure that a further
+ * entry into tty_open can not pick up this tty.
*/
if (pty_master) {
if (--o_tty->count < 0) {
@@ -1766,12 +1776,13 @@ int tty_release(struct inode *inode, struct file *filp)
}
mutex_unlock(&tty_mutex);
+ tty_unlock_pair(tty, o_tty);
+ /* At this point the TTY_CLOSING flag should ensure a dead tty
+ cannot be re-opened by a racing opener */
/* check whether both sides are closing ... */
- if (!tty_closing || (o_tty && !o_tty_closing)) {
- tty_unlock();
+ if (!tty_closing || (o_tty && !o_tty_closing))
return 0;
- }
#ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "%s: freeing tty structure...\n", __func__);
@@ -1782,14 +1793,17 @@ int tty_release(struct inode *inode, struct file *filp)
tty_ldisc_release(tty, o_tty);
/*
* The release_tty function takes care of the details of clearing
- * the slots and preserving the termios structure.
+ * the slots and preserving the termios structure. The tty_unlock_pair
+ * should be safe as we keep a kref while the tty is locked (so the
+ * unlock never unlocks a freed tty).
*/
+ mutex_lock(&tty_mutex);
release_tty(tty, idx);
+ mutex_unlock(&tty_mutex);
/* Make this pty number available for reallocation */
if (devpts)
devpts_kill_index(inode, idx);
- tty_unlock();
return 0;
}
@@ -1893,6 +1907,9 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
* Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev.
* tty->count should protect the rest.
* ->siglock protects ->signal/->sighand
+ *
+ * Note: the tty_unlock/lock cases without a ref are only safe due to
+ * tty_mutex
*/
static int tty_open(struct inode *inode, struct file *filp)
@@ -1916,8 +1933,7 @@ retry_open:
retval = 0;
mutex_lock(&tty_mutex);
- tty_lock();
-
+ /* This is protected by the tty_mutex */
tty = tty_open_current_tty(device, filp);
if (IS_ERR(tty)) {
retval = PTR_ERR(tty);
@@ -1938,17 +1954,19 @@ retry_open:
}
if (tty) {
+ tty_lock(tty);
retval = tty_reopen(tty);
- if (retval)
+ if (retval < 0) {
+ tty_unlock(tty);
tty = ERR_PTR(retval);
- } else
+ }
+ } else /* Returns with the tty_lock held for now */
tty = tty_init_dev(driver, index);
mutex_unlock(&tty_mutex);
if (driver)
tty_driver_kref_put(driver);
if (IS_ERR(tty)) {
- tty_unlock();
retval = PTR_ERR(tty);
goto err_file;
}
@@ -1977,7 +1995,7 @@ retry_open:
printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__,
retval, tty->name);
#endif
- tty_unlock(); /* need to call tty_release without BTM */
+ tty_unlock(tty); /* need to call tty_release without BTM */
tty_release(inode, filp);
if (retval != -ERESTARTSYS)
return retval;
@@ -1989,17 +2007,15 @@ retry_open:
/*
* Need to reset f_op in case a hangup happened.
*/
- tty_lock();
if (filp->f_op == &hung_up_tty_fops)
filp->f_op = &tty_fops;
- tty_unlock();
goto retry_open;
}
- tty_unlock();
+ tty_unlock(tty);
mutex_lock(&tty_mutex);
- tty_lock();
+ tty_lock(tty);
spin_lock_irq(&current->sighand->siglock);
if (!noctty &&
current->signal->leader &&
@@ -2007,11 +2023,10 @@ retry_open:
tty->session == NULL)
__proc_set_tty(current, tty);
spin_unlock_irq(&current->sighand->siglock);
- tty_unlock();
+ tty_unlock(tty);
mutex_unlock(&tty_mutex);
return 0;
err_unlock:
- tty_unlock();
mutex_unlock(&tty_mutex);
/* after locks to avoid deadlock */
if (!IS_ERR_OR_NULL(driver))
@@ -2094,10 +2109,13 @@ out:
static int tty_fasync(int fd, struct file *filp, int on)
{
+ struct tty_struct *tty = file_tty(filp);
int retval;
- tty_lock();
+
+ tty_lock(tty);
retval = __tty_fasync(fd, filp, on);
- tty_unlock();
+ tty_unlock(tty);
+
return retval;
}
@@ -2756,7 +2774,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (ld->ops->ioctl) {
retval = ld->ops->ioctl(tty, file, cmd, arg);
if (retval == -ENOIOCTLCMD)
- retval = -EINVAL;
+ retval = -ENOTTY;
}
tty_ldisc_deref(ld);
return retval;
@@ -2934,6 +2952,7 @@ void initialize_tty_struct(struct tty_struct *tty,
tty->pgrp = NULL;
tty->overrun_time = jiffies;
tty_buffer_init(tty);
+ mutex_init(&tty->legacy_mutex);
mutex_init(&tty->termios_mutex);
mutex_init(&tty->ldisc_mutex);
init_waitqueue_head(&tty->write_wait);
@@ -2991,6 +3010,15 @@ EXPORT_SYMBOL_GPL(tty_put_char);
struct class *tty_class;
+static int tty_cdev_add(struct tty_driver *driver, dev_t dev,
+ unsigned int index, unsigned int count)
+{
+ /* init here, since reused cdevs cause crashes */
+ cdev_init(&driver->cdevs[index], &tty_fops);
+ driver->cdevs[index].owner = driver->owner;
+ return cdev_add(&driver->cdevs[index], dev, count);
+}
+
/**
* tty_register_device - register a tty device
* @driver: the tty driver that describes the tty device
@@ -3013,8 +3041,46 @@ struct class *tty_class;
struct device *tty_register_device(struct tty_driver *driver, unsigned index,
struct device *device)
{
+ return tty_register_device_attr(driver, index, device, NULL, NULL);
+}
+EXPORT_SYMBOL(tty_register_device);
+
+static void tty_device_create_release(struct device *dev)
+{
+ pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
+ kfree(dev);
+}
+
+/**
+ * tty_register_device_attr - register a tty device
+ * @driver: the tty driver that describes the tty device
+ * @index: the index in the tty driver for this tty device
+ * @device: a struct device that is associated with this tty device.
+ * This field is optional, if there is no known struct device
+ * for this tty device it can be set to NULL safely.
+ * @drvdata: Driver data to be set to device.
+ * @attr_grp: Attribute group to be set on device.
+ *
+ * Returns a pointer to the struct device for this tty device
+ * (or ERR_PTR(-EFOO) on error).
+ *
+ * This call is required to be made to register an individual tty device
+ * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If
+ * that bit is not set, this function should not be called by a tty
+ * driver.
+ *
+ * Locking: ??
+ */
+struct device *tty_register_device_attr(struct tty_driver *driver,
+ unsigned index, struct device *device,
+ void *drvdata,
+ const struct attribute_group **attr_grp)
+{
char name[64];
- dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
+ dev_t devt = MKDEV(driver->major, driver->minor_start) + index;
+ struct device *dev = NULL;
+ int retval = -ENODEV;
+ bool cdev = false;
if (index >= driver->num) {
printk(KERN_ERR "Attempt to register invalid tty line number "
@@ -3027,9 +3093,40 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index,
else
tty_line_name(driver, index, name);
- return device_create(tty_class, device, dev, NULL, name);
+ if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) {
+ retval = tty_cdev_add(driver, devt, index, 1);
+ if (retval)
+ goto error;
+ cdev = true;
+ }
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ dev->devt = devt;
+ dev->class = tty_class;
+ dev->parent = device;
+ dev->release = tty_device_create_release;
+ dev_set_name(dev, "%s", name);
+ dev->groups = attr_grp;
+ dev_set_drvdata(dev, drvdata);
+
+ retval = device_register(dev);
+ if (retval)
+ goto error;
+
+ return dev;
+
+error:
+ put_device(dev);
+ if (cdev)
+ cdev_del(&driver->cdevs[index]);
+ return ERR_PTR(retval);
}
-EXPORT_SYMBOL(tty_register_device);
+EXPORT_SYMBOL_GPL(tty_register_device_attr);
/**
* tty_unregister_device - unregister a tty device
@@ -3046,31 +3143,82 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index)
{
device_destroy(tty_class,
MKDEV(driver->major, driver->minor_start) + index);
+ if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC))
+ cdev_del(&driver->cdevs[index]);
}
EXPORT_SYMBOL(tty_unregister_device);
-struct tty_driver *__alloc_tty_driver(int lines, struct module *owner)
+/**
+ * __tty_alloc_driver -- allocate tty driver
+ * @lines: count of lines this driver can handle at most
+ * @owner: module which is repsonsible for this driver
+ * @flags: some of TTY_DRIVER_* flags, will be set in driver->flags
+ *
+ * This should not be called directly, some of the provided macros should be
+ * used instead. Use IS_ERR and friends on @retval.
+ */
+struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
+ unsigned long flags)
{
struct tty_driver *driver;
+ unsigned int cdevs = 1;
+ int err;
+
+ if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1))
+ return ERR_PTR(-EINVAL);
driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
- if (driver) {
- kref_init(&driver->kref);
- driver->magic = TTY_DRIVER_MAGIC;
- driver->num = lines;
- driver->owner = owner;
- /* later we'll move allocation of tables here */
+ if (!driver)
+ return ERR_PTR(-ENOMEM);
+
+ kref_init(&driver->kref);
+ driver->magic = TTY_DRIVER_MAGIC;
+ driver->num = lines;
+ driver->owner = owner;
+ driver->flags = flags;
+
+ if (!(flags & TTY_DRIVER_DEVPTS_MEM)) {
+ driver->ttys = kcalloc(lines, sizeof(*driver->ttys),
+ GFP_KERNEL);
+ driver->termios = kcalloc(lines, sizeof(*driver->termios),
+ GFP_KERNEL);
+ if (!driver->ttys || !driver->termios) {
+ err = -ENOMEM;
+ goto err_free_all;
+ }
}
+
+ if (!(flags & TTY_DRIVER_DYNAMIC_ALLOC)) {
+ driver->ports = kcalloc(lines, sizeof(*driver->ports),
+ GFP_KERNEL);
+ if (!driver->ports) {
+ err = -ENOMEM;
+ goto err_free_all;
+ }
+ cdevs = lines;
+ }
+
+ driver->cdevs = kcalloc(cdevs, sizeof(*driver->cdevs), GFP_KERNEL);
+ if (!driver->cdevs) {
+ err = -ENOMEM;
+ goto err_free_all;
+ }
+
return driver;
+err_free_all:
+ kfree(driver->ports);
+ kfree(driver->ttys);
+ kfree(driver->termios);
+ kfree(driver);
+ return ERR_PTR(err);
}
-EXPORT_SYMBOL(__alloc_tty_driver);
+EXPORT_SYMBOL(__tty_alloc_driver);
static void destruct_tty_driver(struct kref *kref)
{
struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
int i;
struct ktermios *tp;
- void *p;
if (driver->flags & TTY_DRIVER_INSTALLED) {
/*
@@ -3087,13 +3235,14 @@ static void destruct_tty_driver(struct kref *kref)
if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
tty_unregister_device(driver, i);
}
- p = driver->ttys;
proc_tty_unregister_driver(driver);
- driver->ttys = NULL;
- driver->termios = NULL;
- kfree(p);
- cdev_del(&driver->cdev);
+ if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)
+ cdev_del(&driver->cdevs[0]);
}
+ kfree(driver->cdevs);
+ kfree(driver->ports);
+ kfree(driver->termios);
+ kfree(driver->ttys);
kfree(driver);
}
@@ -3124,15 +3273,8 @@ int tty_register_driver(struct tty_driver *driver)
int error;
int i;
dev_t dev;
- void **p = NULL;
struct device *d;
- if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
- p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
- }
-
if (!driver->major) {
error = alloc_chrdev_region(&dev, driver->minor_start,
driver->num, driver->name);
@@ -3144,28 +3286,13 @@ int tty_register_driver(struct tty_driver *driver)
dev = MKDEV(driver->major, driver->minor_start);
error = register_chrdev_region(dev, driver->num, driver->name);
}
- if (error < 0) {
- kfree(p);
- return error;
- }
+ if (error < 0)
+ goto err;
- if (p) {
- driver->ttys = (struct tty_struct **)p;
- driver->termios = (struct ktermios **)(p + driver->num);
- } else {
- driver->ttys = NULL;
- driver->termios = NULL;
- }
-
- cdev_init(&driver->cdev, &tty_fops);
- driver->cdev.owner = driver->owner;
- error = cdev_add(&driver->cdev, dev, driver->num);
- if (error) {
- unregister_chrdev_region(dev, driver->num);
- driver->ttys = NULL;
- driver->termios = NULL;
- kfree(p);
- return error;
+ if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) {
+ error = tty_cdev_add(driver, dev, 0, driver->num);
+ if (error)
+ goto err_unreg_char;
}
mutex_lock(&tty_mutex);
@@ -3177,7 +3304,7 @@ int tty_register_driver(struct tty_driver *driver)
d = tty_register_device(driver, i, NULL);
if (IS_ERR(d)) {
error = PTR_ERR(d);
- goto err;
+ goto err_unreg_devs;
}
}
}
@@ -3185,7 +3312,7 @@ int tty_register_driver(struct tty_driver *driver)
driver->flags |= TTY_DRIVER_INSTALLED;
return 0;
-err:
+err_unreg_devs:
for (i--; i >= 0; i--)
tty_unregister_device(driver, i);
@@ -3193,13 +3320,11 @@ err:
list_del(&driver->tty_drivers);
mutex_unlock(&tty_mutex);
+err_unreg_char:
unregister_chrdev_region(dev, driver->num);
- driver->ttys = NULL;
- driver->termios = NULL;
- kfree(p);
+err:
return error;
}
-
EXPORT_SYMBOL(tty_register_driver);
/*
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index a1b9a2f68567..12b1fa0f4f86 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -410,7 +410,7 @@ EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
{
- tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
+ tty_termios_encode_baud_rate(&tty->termios, ibaud, obaud);
}
EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
@@ -427,7 +427,7 @@ EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
speed_t tty_get_baud_rate(struct tty_struct *tty)
{
- speed_t baud = tty_termios_baud_rate(tty->termios);
+ speed_t baud = tty_termios_baud_rate(&tty->termios);
if (baud == 38400 && tty->alt_speed) {
if (!tty->warned) {
@@ -509,14 +509,14 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
/* FIXME: we need to decide on some locking/ordering semantics
for the set_termios notification eventually */
mutex_lock(&tty->termios_mutex);
- old_termios = *tty->termios;
- *tty->termios = *new_termios;
- unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
+ old_termios = tty->termios;
+ tty->termios = *new_termios;
+ unset_locked_termios(&tty->termios, &old_termios, &tty->termios_locked);
/* See if packet mode change of state. */
if (tty->link && tty->link->packet) {
int extproc = (old_termios.c_lflag & EXTPROC) |
- (tty->termios->c_lflag & EXTPROC);
+ (tty->termios.c_lflag & EXTPROC);
int old_flow = ((old_termios.c_iflag & IXON) &&
(old_termios.c_cc[VSTOP] == '\023') &&
(old_termios.c_cc[VSTART] == '\021'));
@@ -542,7 +542,7 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
if (tty->ops->set_termios)
(*tty->ops->set_termios)(tty, &old_termios);
else
- tty_termios_copy_hw(tty->termios, &old_termios);
+ tty_termios_copy_hw(&tty->termios, &old_termios);
ld = tty_ldisc_ref(tty);
if (ld != NULL) {
@@ -578,7 +578,7 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
return retval;
mutex_lock(&tty->termios_mutex);
- memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
+ tmp_termios = tty->termios;
mutex_unlock(&tty->termios_mutex);
if (opt & TERMIOS_TERMIO) {
@@ -632,14 +632,14 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
{
mutex_lock(&tty->termios_mutex);
- memcpy(kterm, tty->termios, sizeof(struct ktermios));
+ *kterm = tty->termios;
mutex_unlock(&tty->termios_mutex);
}
static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
{
mutex_lock(&tty->termios_mutex);
- memcpy(kterm, tty->termios_locked, sizeof(struct ktermios));
+ *kterm = tty->termios_locked;
mutex_unlock(&tty->termios_mutex);
}
@@ -707,16 +707,16 @@ static int get_sgflags(struct tty_struct *tty)
{
int flags = 0;
- if (!(tty->termios->c_lflag & ICANON)) {
- if (tty->termios->c_lflag & ISIG)
+ if (!(tty->termios.c_lflag & ICANON)) {
+ if (tty->termios.c_lflag & ISIG)
flags |= 0x02; /* cbreak */
else
flags |= 0x20; /* raw */
}
- if (tty->termios->c_lflag & ECHO)
+ if (tty->termios.c_lflag & ECHO)
flags |= 0x08; /* echo */
- if (tty->termios->c_oflag & OPOST)
- if (tty->termios->c_oflag & ONLCR)
+ if (tty->termios.c_oflag & OPOST)
+ if (tty->termios.c_oflag & ONLCR)
flags |= 0x10; /* crmod */
return flags;
}
@@ -726,10 +726,10 @@ static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
struct sgttyb tmp;
mutex_lock(&tty->termios_mutex);
- tmp.sg_ispeed = tty->termios->c_ispeed;
- tmp.sg_ospeed = tty->termios->c_ospeed;
- tmp.sg_erase = tty->termios->c_cc[VERASE];
- tmp.sg_kill = tty->termios->c_cc[VKILL];
+ tmp.sg_ispeed = tty->termios.c_ispeed;
+ tmp.sg_ospeed = tty->termios.c_ospeed;
+ tmp.sg_erase = tty->termios.c_cc[VERASE];
+ tmp.sg_kill = tty->termios.c_cc[VKILL];
tmp.sg_flags = get_sgflags(tty);
mutex_unlock(&tty->termios_mutex);
@@ -787,7 +787,7 @@ static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
return -EFAULT;
mutex_lock(&tty->termios_mutex);
- termios = *tty->termios;
+ termios = tty->termios;
termios.c_cc[VERASE] = tmp.sg_erase;
termios.c_cc[VKILL] = tmp.sg_kill;
set_sgflags(&termios, tmp.sg_flags);
@@ -808,12 +808,12 @@ static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
struct tchars tmp;
mutex_lock(&tty->termios_mutex);
- tmp.t_intrc = tty->termios->c_cc[VINTR];
- tmp.t_quitc = tty->termios->c_cc[VQUIT];
- tmp.t_startc = tty->termios->c_cc[VSTART];
- tmp.t_stopc = tty->termios->c_cc[VSTOP];
- tmp.t_eofc = tty->termios->c_cc[VEOF];
- tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
+ tmp.t_intrc = tty->termios.c_cc[VINTR];
+ tmp.t_quitc = tty->termios.c_cc[VQUIT];
+ tmp.t_startc = tty->termios.c_cc[VSTART];
+ tmp.t_stopc = tty->termios.c_cc[VSTOP];
+ tmp.t_eofc = tty->termios.c_cc[VEOF];
+ tmp.t_brkc = tty->termios.c_cc[VEOL2]; /* what is brkc anyway? */
mutex_unlock(&tty->termios_mutex);
return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@ -825,12 +825,12 @@ static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
if (copy_from_user(&tmp, tchars, sizeof(tmp)))
return -EFAULT;
mutex_lock(&tty->termios_mutex);
- tty->termios->c_cc[VINTR] = tmp.t_intrc;
- tty->termios->c_cc[VQUIT] = tmp.t_quitc;
- tty->termios->c_cc[VSTART] = tmp.t_startc;
- tty->termios->c_cc[VSTOP] = tmp.t_stopc;
- tty->termios->c_cc[VEOF] = tmp.t_eofc;
- tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
+ tty->termios.c_cc[VINTR] = tmp.t_intrc;
+ tty->termios.c_cc[VQUIT] = tmp.t_quitc;
+ tty->termios.c_cc[VSTART] = tmp.t_startc;
+ tty->termios.c_cc[VSTOP] = tmp.t_stopc;
+ tty->termios.c_cc[VEOF] = tmp.t_eofc;
+ tty->termios.c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
mutex_unlock(&tty->termios_mutex);
return 0;
}
@@ -842,14 +842,14 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
struct ltchars tmp;
mutex_lock(&tty->termios_mutex);
- tmp.t_suspc = tty->termios->c_cc[VSUSP];
+ tmp.t_suspc = tty->termios.c_cc[VSUSP];
/* what is dsuspc anyway? */
- tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
- tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
+ tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
+ tmp.t_rprntc = tty->termios.c_cc[VREPRINT];
/* what is flushc anyway? */
- tmp.t_flushc = tty->termios->c_cc[VEOL2];
- tmp.t_werasc = tty->termios->c_cc[VWERASE];
- tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
+ tmp.t_flushc = tty->termios.c_cc[VEOL2];
+ tmp.t_werasc = tty->termios.c_cc[VWERASE];
+ tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
mutex_unlock(&tty->termios_mutex);
return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@ -862,14 +862,14 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
return -EFAULT;
mutex_lock(&tty->termios_mutex);
- tty->termios->c_cc[VSUSP] = tmp.t_suspc;
+ tty->termios.c_cc[VSUSP] = tmp.t_suspc;
/* what is dsuspc anyway? */
- tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
- tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
+ tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
+ tty->termios.c_cc[VREPRINT] = tmp.t_rprntc;
/* what is flushc anyway? */
- tty->termios->c_cc[VEOL2] = tmp.t_flushc;
- tty->termios->c_cc[VWERASE] = tmp.t_werasc;
- tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
+ tty->termios.c_cc[VEOL2] = tmp.t_flushc;
+ tty->termios.c_cc[VWERASE] = tmp.t_werasc;
+ tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
mutex_unlock(&tty->termios_mutex);
return 0;
}
@@ -920,12 +920,12 @@ static int tty_change_softcar(struct tty_struct *tty, int arg)
struct ktermios old;
mutex_lock(&tty->termios_mutex);
- old = *tty->termios;
- tty->termios->c_cflag &= ~CLOCAL;
- tty->termios->c_cflag |= bit;
+ old = tty->termios;
+ tty->termios.c_cflag &= ~CLOCAL;
+ tty->termios.c_cflag |= bit;
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old);
- if ((tty->termios->c_cflag & CLOCAL) != bit)
+ if ((tty->termios.c_cflag & CLOCAL) != bit)
ret = -EINVAL;
mutex_unlock(&tty->termios_mutex);
return ret;
@@ -1031,7 +1031,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
(struct termios __user *) arg))
return -EFAULT;
mutex_lock(&real_tty->termios_mutex);
- memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
+ real_tty->termios_locked = kterm;
mutex_unlock(&real_tty->termios_mutex);
return 0;
#else
@@ -1048,7 +1048,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
(struct termios __user *) arg))
return -EFAULT;
mutex_lock(&real_tty->termios_mutex);
- memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
+ real_tty->termios_locked = kterm;
mutex_unlock(&real_tty->termios_mutex);
return ret;
#endif
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 6f99c9959f0c..4d7b56268c79 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -413,7 +413,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush);
static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
{
mutex_lock(&tty->termios_mutex);
- tty->termios->c_line = num;
+ tty->termios.c_line = num;
mutex_unlock(&tty->termios_mutex);
}
@@ -568,7 +568,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
if (IS_ERR(new_ldisc))
return PTR_ERR(new_ldisc);
- tty_lock();
+ tty_lock(tty);
/*
* We need to look at the tty locking here for pty/tty pairs
* when both sides try to change in parallel.
@@ -582,12 +582,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
*/
if (tty->ldisc->ops->num == ldisc) {
- tty_unlock();
+ tty_unlock(tty);
tty_ldisc_put(new_ldisc);
return 0;
}
- tty_unlock();
+ tty_unlock(tty);
/*
* Problem: What do we do if this blocks ?
* We could deadlock here
@@ -595,7 +595,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
tty_wait_until_sent(tty, 0);
- tty_lock();
+ tty_lock(tty);
mutex_lock(&tty->ldisc_mutex);
/*
@@ -605,10 +605,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
mutex_unlock(&tty->ldisc_mutex);
- tty_unlock();
+ tty_unlock(tty);
wait_event(tty_ldisc_wait,
test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
- tty_lock();
+ tty_lock(tty);
mutex_lock(&tty->ldisc_mutex);
}
@@ -623,7 +623,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
o_ldisc = tty->ldisc;
- tty_unlock();
+ tty_unlock(tty);
/*
* Make sure we don't change while someone holds a
* reference to the line discipline. The TTY_LDISC bit
@@ -650,7 +650,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
retval = tty_ldisc_wait_idle(tty, 5 * HZ);
- tty_lock();
+ tty_lock(tty);
mutex_lock(&tty->ldisc_mutex);
/* handle wait idle failure locked */
@@ -665,7 +665,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
mutex_unlock(&tty->ldisc_mutex);
tty_ldisc_put(new_ldisc);
- tty_unlock();
+ tty_unlock(tty);
return -EIO;
}
@@ -708,7 +708,7 @@ enable:
if (o_work)
schedule_work(&o_tty->buf.work);
mutex_unlock(&tty->ldisc_mutex);
- tty_unlock();
+ tty_unlock(tty);
return retval;
}
@@ -722,9 +722,9 @@ enable:
static void tty_reset_termios(struct tty_struct *tty)
{
mutex_lock(&tty->termios_mutex);
- *tty->termios = tty->driver->init_termios;
- tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
- tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+ tty->termios = tty->driver->init_termios;
+ tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios);
+ tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios);
mutex_unlock(&tty->termios_mutex);
}
@@ -816,11 +816,11 @@ void tty_ldisc_hangup(struct tty_struct *tty)
* need to wait for another function taking the BTM
*/
clear_bit(TTY_LDISC, &tty->flags);
- tty_unlock();
+ tty_unlock(tty);
cancel_work_sync(&tty->buf.work);
mutex_unlock(&tty->ldisc_mutex);
retry:
- tty_lock();
+ tty_lock(tty);
mutex_lock(&tty->ldisc_mutex);
/* At this point we have a closed ldisc and we want to
@@ -831,7 +831,7 @@ retry:
if (atomic_read(&tty->ldisc->users) != 1) {
char cur_n[TASK_COMM_LEN], tty_n[64];
long timeout = 3 * HZ;
- tty_unlock();
+ tty_unlock(tty);
while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
timeout = MAX_SCHEDULE_TIMEOUT;
@@ -846,7 +846,7 @@ retry:
if (reset == 0) {
- if (!tty_ldisc_reinit(tty, tty->termios->c_line))
+ if (!tty_ldisc_reinit(tty, tty->termios.c_line))
err = tty_ldisc_open(tty, tty->ldisc);
else
err = 1;
@@ -894,6 +894,23 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
tty_ldisc_enable(tty);
return 0;
}
+
+static void tty_ldisc_kill(struct tty_struct *tty)
+{
+ mutex_lock(&tty->ldisc_mutex);
+ /*
+ * Now kill off the ldisc
+ */
+ tty_ldisc_close(tty, tty->ldisc);
+ tty_ldisc_put(tty->ldisc);
+ /* Force an oops if we mess this up */
+ tty->ldisc = NULL;
+
+ /* Ensure the next open requests the N_TTY ldisc */
+ tty_set_termios_ldisc(tty, N_TTY);
+ mutex_unlock(&tty->ldisc_mutex);
+}
+
/**
* tty_ldisc_release - release line discipline
* @tty: tty being shut down
@@ -912,28 +929,21 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
* race with the set_ldisc code path.
*/
- tty_unlock();
+ tty_lock_pair(tty, o_tty);
tty_ldisc_halt(tty);
tty_ldisc_flush_works(tty);
- tty_lock();
-
- mutex_lock(&tty->ldisc_mutex);
- /*
- * Now kill off the ldisc
- */
- tty_ldisc_close(tty, tty->ldisc);
- tty_ldisc_put(tty->ldisc);
- /* Force an oops if we mess this up */
- tty->ldisc = NULL;
-
- /* Ensure the next open requests the N_TTY ldisc */
- tty_set_termios_ldisc(tty, N_TTY);
- mutex_unlock(&tty->ldisc_mutex);
+ if (o_tty) {
+ tty_ldisc_halt(o_tty);
+ tty_ldisc_flush_works(o_tty);
+ }
/* This will need doing differently if we need to lock */
+ tty_ldisc_kill(tty);
+
if (o_tty)
- tty_ldisc_release(o_tty, NULL);
+ tty_ldisc_kill(o_tty);
+ tty_unlock_pair(tty, o_tty);
/* And the memory resources remaining (buffers, termios) will be
disposed of when the kref hits zero */
}
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c
index 9ff986c32a21..67feac9e6ebb 100644
--- a/drivers/tty/tty_mutex.c
+++ b/drivers/tty/tty_mutex.c
@@ -4,29 +4,70 @@
#include <linux/semaphore.h>
#include <linux/sched.h>
-/*
- * The 'big tty mutex'
- *
- * This mutex is taken and released by tty_lock() and tty_unlock(),
- * replacing the older big kernel lock.
- * It can no longer be taken recursively, and does not get
- * released implicitly while sleeping.
- *
- * Don't use in new code.
- */
-static DEFINE_MUTEX(big_tty_mutex);
+/* Legacy tty mutex glue */
+
+enum {
+ TTY_MUTEX_NORMAL,
+ TTY_MUTEX_NESTED,
+};
/*
* Getting the big tty mutex.
*/
-void __lockfunc tty_lock(void)
+
+static void __lockfunc tty_lock_nested(struct tty_struct *tty,
+ unsigned int subclass)
{
- mutex_lock(&big_tty_mutex);
+ if (tty->magic != TTY_MAGIC) {
+ printk(KERN_ERR "L Bad %p\n", tty);
+ WARN_ON(1);
+ return;
+ }
+ tty_kref_get(tty);
+ mutex_lock_nested(&tty->legacy_mutex, subclass);
+}
+
+void __lockfunc tty_lock(struct tty_struct *tty)
+{
+ return tty_lock_nested(tty, TTY_MUTEX_NORMAL);
}
EXPORT_SYMBOL(tty_lock);
-void __lockfunc tty_unlock(void)
+void __lockfunc tty_unlock(struct tty_struct *tty)
{
- mutex_unlock(&big_tty_mutex);
+ if (tty->magic != TTY_MAGIC) {
+ printk(KERN_ERR "U Bad %p\n", tty);
+ WARN_ON(1);
+ return;
+ }
+ mutex_unlock(&tty->legacy_mutex);
+ tty_kref_put(tty);
}
EXPORT_SYMBOL(tty_unlock);
+
+/*
+ * Getting the big tty mutex for a pair of ttys with lock ordering
+ * On a non pty/tty pair tty2 can be NULL which is just fine.
+ */
+void __lockfunc tty_lock_pair(struct tty_struct *tty,
+ struct tty_struct *tty2)
+{
+ if (tty < tty2) {
+ tty_lock(tty);
+ tty_lock_nested(tty2, TTY_MUTEX_NESTED);
+ } else {
+ if (tty2 && tty2 != tty)
+ tty_lock(tty2);
+ tty_lock_nested(tty, TTY_MUTEX_NESTED);
+ }
+}
+EXPORT_SYMBOL(tty_lock_pair);
+
+void __lockfunc tty_unlock_pair(struct tty_struct *tty,
+ struct tty_struct *tty2)
+{
+ tty_unlock(tty);
+ if (tty2 && tty2 != tty)
+ tty_unlock(tty2);
+}
+EXPORT_SYMBOL(tty_unlock_pair);
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index bf6e238146ae..d7bdd8d0c23f 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -33,6 +33,70 @@ void tty_port_init(struct tty_port *port)
}
EXPORT_SYMBOL(tty_port_init);
+/**
+ * tty_port_link_device - link tty and tty_port
+ * @port: tty_port of the device
+ * @driver: tty_driver for this device
+ * @index: index of the tty
+ *
+ * Provide the tty layer wit ha link from a tty (specified by @index) to a
+ * tty_port (@port). Use this only if neither tty_port_register_device nor
+ * tty_port_install is used in the driver. If used, this has to be called before
+ * tty_register_driver.
+ */
+void tty_port_link_device(struct tty_port *port,
+ struct tty_driver *driver, unsigned index)
+{
+ if (WARN_ON(index >= driver->num))
+ return;
+ driver->ports[index] = port;
+}
+EXPORT_SYMBOL_GPL(tty_port_link_device);
+
+/**
+ * tty_port_register_device - register tty device
+ * @port: tty_port of the device
+ * @driver: tty_driver for this device
+ * @index: index of the tty
+ * @device: parent if exists, otherwise NULL
+ *
+ * It is the same as tty_register_device except the provided @port is linked to
+ * a concrete tty specified by @index. Use this or tty_port_install (or both).
+ * Call tty_port_link_device as a last resort.
+ */
+struct device *tty_port_register_device(struct tty_port *port,
+ struct tty_driver *driver, unsigned index,
+ struct device *device)
+{
+ tty_port_link_device(port, driver, index);
+ return tty_register_device(driver, index, device);
+}
+EXPORT_SYMBOL_GPL(tty_port_register_device);
+
+/**
+ * tty_port_register_device_attr - register tty device
+ * @port: tty_port of the device
+ * @driver: tty_driver for this device
+ * @index: index of the tty
+ * @device: parent if exists, otherwise NULL
+ * @drvdata: Driver data to be set to device.
+ * @attr_grp: Attribute group to be set on device.
+ *
+ * It is the same as tty_register_device_attr except the provided @port is
+ * linked to a concrete tty specified by @index. Use this or tty_port_install
+ * (or both). Call tty_port_link_device as a last resort.
+ */
+struct device *tty_port_register_device_attr(struct tty_port *port,
+ struct tty_driver *driver, unsigned index,
+ struct device *device, void *drvdata,
+ const struct attribute_group **attr_grp)
+{
+ tty_port_link_device(port, driver, index);
+ return tty_register_device_attr(driver, index, device, drvdata,
+ attr_grp);
+}
+EXPORT_SYMBOL_GPL(tty_port_register_device_attr);
+
int tty_port_alloc_xmit_buf(struct tty_port *port)
{
/* We may sleep in get_zeroed_page() */
@@ -230,7 +294,7 @@ int tty_port_block_til_ready(struct tty_port *port,
/* block if port is in the process of being closed */
if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
- wait_event_interruptible_tty(port->close_wait,
+ wait_event_interruptible_tty(tty, port->close_wait,
!(port->flags & ASYNC_CLOSING));
if (port->flags & ASYNC_HUP_NOTIFY)
return -EAGAIN;
@@ -246,7 +310,7 @@ int tty_port_block_til_ready(struct tty_port *port,
}
if (filp->f_flags & O_NONBLOCK) {
/* Indicate we are open */
- if (tty->termios->c_cflag & CBAUD)
+ if (tty->termios.c_cflag & CBAUD)
tty_port_raise_dtr_rts(port);
port->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
@@ -270,7 +334,7 @@ int tty_port_block_til_ready(struct tty_port *port,
while (1) {
/* Indicate we are open */
- if (tty->termios->c_cflag & CBAUD)
+ if (tty->termios.c_cflag & CBAUD)
tty_port_raise_dtr_rts(port);
prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
@@ -296,9 +360,9 @@ int tty_port_block_til_ready(struct tty_port *port,
retval = -ERESTARTSYS;
break;
}
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
finish_wait(&port->open_wait, &wait);
@@ -369,7 +433,7 @@ int tty_port_close_start(struct tty_port *port,
/* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
hang up the line */
- if (tty->termios->c_cflag & HUPCL)
+ if (tty->termios.c_cflag & HUPCL)
tty_port_lower_dtr_rts(port);
/* Don't call port->drop for the last reference. Callers will want
@@ -413,6 +477,24 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty,
}
EXPORT_SYMBOL(tty_port_close);
+/**
+ * tty_port_install - generic tty->ops->install handler
+ * @port: tty_port of the device
+ * @driver: tty_driver for this device
+ * @tty: tty to be installed
+ *
+ * It is the same as tty_standard_install except the provided @port is linked
+ * to a concrete tty specified by @tty. Use this or tty_port_register_device
+ * (or both). Call tty_port_link_device as a last resort.
+ */
+int tty_port_install(struct tty_port *port, struct tty_driver *driver,
+ struct tty_struct *tty)
+{
+ tty->port = port;
+ return tty_standard_install(driver, tty);
+}
+EXPORT_SYMBOL_GPL(tty_port_install);
+
int tty_port_open(struct tty_port *port, struct tty_struct *tty,
struct file *filp)
{
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 48cc6f25cfd3..681765baef69 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -119,6 +119,7 @@ static const int NR_TYPES = ARRAY_SIZE(max_vals);
static struct input_handler kbd_handler;
static DEFINE_SPINLOCK(kbd_event_lock);
+static DEFINE_SPINLOCK(led_lock);
static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */
static bool dead_key_next;
@@ -310,7 +311,7 @@ static void put_queue(struct vc_data *vc, int ch)
if (tty) {
tty_insert_flip_char(tty, ch, 0);
- con_schedule_flip(tty);
+ tty_schedule_flip(tty);
}
}
@@ -325,7 +326,7 @@ static void puts_queue(struct vc_data *vc, char *cp)
tty_insert_flip_char(tty, *cp, 0);
cp++;
}
- con_schedule_flip(tty);
+ tty_schedule_flip(tty);
}
static void applkey(struct vc_data *vc, int key, char mode)
@@ -586,7 +587,7 @@ static void fn_send_intr(struct vc_data *vc)
if (!tty)
return;
tty_insert_flip_char(tty, 0, TTY_BREAK);
- con_schedule_flip(tty);
+ tty_schedule_flip(tty);
}
static void fn_scroll_forw(struct vc_data *vc)
@@ -984,7 +985,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
* or (ii) whatever pattern of lights people want to show using KDSETLED,
* or (iii) specified bits of specified words in kernel memory.
*/
-unsigned char getledstate(void)
+static unsigned char getledstate(void)
{
return ledstate;
}
@@ -992,7 +993,7 @@ unsigned char getledstate(void)
void setledstate(struct kbd_struct *kbd, unsigned int led)
{
unsigned long flags;
- spin_lock_irqsave(&kbd_event_lock, flags);
+ spin_lock_irqsave(&led_lock, flags);
if (!(led & ~7)) {
ledioctl = led;
kbd->ledmode = LED_SHOW_IOCTL;
@@ -1000,7 +1001,7 @@ void setledstate(struct kbd_struct *kbd, unsigned int led)
kbd->ledmode = LED_SHOW_FLAGS;
set_leds();
- spin_unlock_irqrestore(&kbd_event_lock, flags);
+ spin_unlock_irqrestore(&led_lock, flags);
}
static inline unsigned char getleds(void)
@@ -1049,13 +1050,13 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data)
*/
int vt_get_leds(int console, int flag)
{
- unsigned long flags;
struct kbd_struct * kbd = kbd_table + console;
int ret;
+ unsigned long flags;
- spin_lock_irqsave(&kbd_event_lock, flags);
+ spin_lock_irqsave(&led_lock, flags);
ret = vc_kbd_led(kbd, flag);
- spin_unlock_irqrestore(&kbd_event_lock, flags);
+ spin_unlock_irqrestore(&led_lock, flags);
return ret;
}
@@ -1091,11 +1092,11 @@ void vt_set_led_state(int console, int leds)
void vt_kbd_con_start(int console)
{
struct kbd_struct * kbd = kbd_table + console;
-/* unsigned long flags; */
-/* spin_lock_irqsave(&kbd_event_lock, flags); */
+ unsigned long flags;
+ spin_lock_irqsave(&led_lock, flags);
clr_vc_kbd_led(kbd, VC_SCROLLOCK);
set_leds();
-/* spin_unlock_irqrestore(&kbd_event_lock, flags); */
+ spin_unlock_irqrestore(&led_lock, flags);
}
/**
@@ -1104,21 +1105,15 @@ void vt_kbd_con_start(int console)
*
* Handle console stop. This is a wrapper for the VT layer
* so that we can keep kbd knowledge internal
- *
- * FIXME: We eventually need to hold the kbd lock here to protect
- * the LED updating. We can't do it yet because fn_hold calls stop_tty
- * and start_tty under the kbd_event_lock, while normal tty paths
- * don't hold the lock. We probably need to split out an LED lock
- * but not during an -rc release!
*/
void vt_kbd_con_stop(int console)
{
struct kbd_struct * kbd = kbd_table + console;
-/* unsigned long flags; */
-/* spin_lock_irqsave(&kbd_event_lock, flags); */
+ unsigned long flags;
+ spin_lock_irqsave(&led_lock, flags);
set_vc_kbd_led(kbd, VC_SCROLLOCK);
set_leds();
-/* spin_unlock_irqrestore(&kbd_event_lock, flags); */
+ spin_unlock_irqrestore(&led_lock, flags);
}
/*
@@ -1130,7 +1125,12 @@ void vt_kbd_con_stop(int console)
*/
static void kbd_bh(unsigned long dummy)
{
- unsigned char leds = getleds();
+ unsigned char leds;
+ unsigned long flags;
+
+ spin_lock_irqsave(&led_lock, flags);
+ leds = getleds();
+ spin_unlock_irqrestore(&led_lock, flags);
if (leds != ledstate) {
input_handler_for_each_handle(&kbd_handler, &leds,
@@ -2035,11 +2035,11 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm)
return -EPERM;
if (arg & ~0x77)
return -EINVAL;
- spin_lock_irqsave(&kbd_event_lock, flags);
+ spin_lock_irqsave(&led_lock, flags);
kbd->ledflagstate = (arg & 7);
kbd->default_ledflagstate = ((arg >> 4) & 7);
set_leds();
- spin_unlock_irqrestore(&kbd_event_lock, flags);
+ spin_unlock_irqrestore(&led_lock, flags);
return 0;
/* the ioctls below only set the lights, not the functions */
@@ -2134,8 +2134,10 @@ void vt_reset_keyboard(int console)
clr_vc_kbd_mode(kbd, VC_CRLF);
kbd->lockstate = 0;
kbd->slockstate = 0;
+ spin_lock(&led_lock);
kbd->ledmode = LED_SHOW_FLAGS;
kbd->ledflagstate = kbd->default_ledflagstate;
+ spin_unlock(&led_lock);
/* do not do set_leds here because this causes an endless tasklet loop
when the keyboard hasn't been initialized yet */
spin_unlock_irqrestore(&kbd_event_lock, flags);
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 84cbf298c094..999ca63afdef 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -537,45 +537,27 @@ void complement_pos(struct vc_data *vc, int offset)
static void insert_char(struct vc_data *vc, unsigned int nr)
{
- unsigned short *p, *q = (unsigned short *)vc->vc_pos;
+ unsigned short *p = (unsigned short *) vc->vc_pos;
- p = q + vc->vc_cols - nr - vc->vc_x;
- while (--p >= q)
- scr_writew(scr_readw(p), p + nr);
- scr_memsetw(q, vc->vc_video_erase_char, nr * 2);
+ scr_memmovew(p + nr, p, vc->vc_cols - vc->vc_x);
+ scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
vc->vc_need_wrap = 0;
- if (DO_UPDATE(vc)) {
- unsigned short oldattr = vc->vc_attr;
- vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1,
- vc->vc_cols - vc->vc_x - nr);
- vc->vc_attr = vc->vc_video_erase_char >> 8;
- while (nr--)
- vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr);
- vc->vc_attr = oldattr;
- }
+ if (DO_UPDATE(vc))
+ do_update_region(vc, (unsigned long) p,
+ (vc->vc_cols - vc->vc_x) / 2 + 1);
}
static void delete_char(struct vc_data *vc, unsigned int nr)
{
- unsigned int i = vc->vc_x;
- unsigned short *p = (unsigned short *)vc->vc_pos;
+ unsigned short *p = (unsigned short *) vc->vc_pos;
- while (++i <= vc->vc_cols - nr) {
- scr_writew(scr_readw(p+nr), p);
- p++;
- }
- scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
+ scr_memcpyw(p, p + nr, vc->vc_cols - vc->vc_x - nr);
+ scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char,
+ nr * 2);
vc->vc_need_wrap = 0;
- if (DO_UPDATE(vc)) {
- unsigned short oldattr = vc->vc_attr;
- vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1,
- vc->vc_cols - vc->vc_x - nr);
- vc->vc_attr = vc->vc_video_erase_char >> 8;
- while (nr--)
- vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y,
- vc->vc_cols - 1 - nr);
- vc->vc_attr = oldattr;
- }
+ if (DO_UPDATE(vc))
+ do_update_region(vc, (unsigned long) p,
+ (vc->vc_cols - vc->vc_x) / 2);
}
static int softcursor_original;
@@ -1172,45 +1154,26 @@ static void csi_J(struct vc_data *vc, int vpar)
case 0: /* erase from cursor to end of display */
count = (vc->vc_scr_end - vc->vc_pos) >> 1;
start = (unsigned short *)vc->vc_pos;
- if (DO_UPDATE(vc)) {
- /* do in two stages */
- vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
- vc->vc_cols - vc->vc_x);
- vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0,
- vc->vc_rows - vc->vc_y - 1,
- vc->vc_cols);
- }
break;
case 1: /* erase from start to cursor */
count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
start = (unsigned short *)vc->vc_origin;
- if (DO_UPDATE(vc)) {
- /* do in two stages */
- vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y,
- vc->vc_cols);
- vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
- 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;
- if (DO_UPDATE(vc))
- vc->vc_sw->con_clear(vc, 0, 0,
- vc->vc_rows,
- vc->vc_cols);
break;
default:
return;
}
scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
+ if (DO_UPDATE(vc))
+ do_update_region(vc, (unsigned long) start, count);
vc->vc_need_wrap = 0;
}
@@ -1223,29 +1186,22 @@ static void csi_K(struct vc_data *vc, int vpar)
case 0: /* erase from cursor to end of line */
count = vc->vc_cols - vc->vc_x;
start = (unsigned short *)vc->vc_pos;
- if (DO_UPDATE(vc))
- vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
- vc->vc_cols - vc->vc_x);
break;
case 1: /* erase from start of line to cursor */
start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
count = vc->vc_x + 1;
- if (DO_UPDATE(vc))
- vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
- vc->vc_x + 1);
break;
case 2: /* erase whole line */
start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
count = vc->vc_cols;
- if (DO_UPDATE(vc))
- vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
- vc->vc_cols);
break;
default:
return;
}
scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
vc->vc_need_wrap = 0;
+ if (DO_UPDATE(vc))
+ do_update_region(vc, (unsigned long) start, count);
}
static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */
@@ -1380,7 +1336,7 @@ static void respond_string(const char *p, struct tty_struct *tty)
tty_insert_flip_char(tty, *p, 0);
p++;
}
- con_schedule_flip(tty);
+ tty_schedule_flip(tty);
}
static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
@@ -2792,41 +2748,52 @@ static void con_flush_chars(struct tty_struct *tty)
/*
* Allocate the console screen memory.
*/
-static int con_open(struct tty_struct *tty, struct file *filp)
+static int con_install(struct tty_driver *driver, struct tty_struct *tty)
{
unsigned int currcons = tty->index;
- int ret = 0;
+ struct vc_data *vc;
+ int ret;
console_lock();
- if (tty->driver_data == NULL) {
- ret = vc_allocate(currcons);
- if (ret == 0) {
- struct vc_data *vc = vc_cons[currcons].d;
+ ret = vc_allocate(currcons);
+ if (ret)
+ goto unlock;
- /* Still being freed */
- if (vc->port.tty) {
- console_unlock();
- return -ERESTARTSYS;
- }
- tty->driver_data = vc;
- vc->port.tty = tty;
+ vc = vc_cons[currcons].d;
- if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
- tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
- tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
- }
- if (vc->vc_utf)
- tty->termios->c_iflag |= IUTF8;
- else
- tty->termios->c_iflag &= ~IUTF8;
- console_unlock();
- return ret;
- }
+ /* Still being freed */
+ if (vc->port.tty) {
+ ret = -ERESTARTSYS;
+ goto unlock;
}
+
+ ret = tty_port_install(&vc->port, driver, tty);
+ if (ret)
+ goto unlock;
+
+ tty->driver_data = vc;
+ vc->port.tty = tty;
+
+ if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
+ tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
+ tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
+ }
+ if (vc->vc_utf)
+ tty->termios.c_iflag |= IUTF8;
+ else
+ tty->termios.c_iflag &= ~IUTF8;
+unlock:
console_unlock();
return ret;
}
+static int con_open(struct tty_struct *tty, struct file *filp)
+{
+ /* everything done in install */
+ return 0;
+}
+
+
static void con_close(struct tty_struct *tty, struct file *filp)
{
/* Nothing to do - we defer to shutdown */
@@ -2839,7 +2806,6 @@ static void con_shutdown(struct tty_struct *tty)
console_lock();
vc->port.tty = NULL;
console_unlock();
- tty_shutdown(tty);
}
static int default_italic_color = 2; // green (ASCII)
@@ -2947,6 +2913,7 @@ static int __init con_init(void)
console_initcall(con_init);
static const struct tty_operations con_ops = {
+ .install = con_install,
.open = con_open,
.close = con_close,
.write = con_write,
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index f763ed7ba91e..ff7b5a8d501c 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -826,7 +826,7 @@ static void acm_tty_set_termios(struct tty_struct *tty,
struct ktermios *termios_old)
{
struct acm *acm = tty->driver_data;
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
struct usb_cdc_line_coding newline;
int newctrl = acm->ctrlout;
@@ -1299,7 +1299,8 @@ skip_countries:
usb_set_intfdata(data_interface, acm);
usb_get_intf(control_interface);
- tty_register_device(acm_tty_driver, minor, &control_interface->dev);
+ tty_port_register_device(&acm->port, acm_tty_driver, minor,
+ &control_interface->dev);
return 0;
alloc_fail7:
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index da6d479ff9a6..f1739526820f 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -1133,7 +1133,8 @@ int gserial_setup(struct usb_gadget *g, unsigned count)
for (i = 0; i < count; i++) {
struct device *tty_dev;
- tty_dev = tty_register_device(gs_tty_driver, i, &g->dev);
+ tty_dev = tty_port_register_device(&ports[i].port->port,
+ gs_tty_driver, i, &g->dev);
if (IS_ERR(tty_dev))
pr_warning("%s: no classdev for port %d, err %ld\n",
__func__, i, PTR_ERR(tty_dev));
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index f8ce97d8b0ad..3b98fb733362 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -215,7 +215,7 @@ static void ark3116_release(struct usb_serial *serial)
static void ark3116_init_termios(struct tty_struct *tty)
{
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
*termios = tty_std_termios;
termios->c_cflag = B9600 | CS8
| CREAD | HUPCL | CLOCAL;
@@ -229,7 +229,7 @@ static void ark3116_set_termios(struct tty_struct *tty,
{
struct usb_serial *serial = port->serial;
struct ark3116_private *priv = usb_get_serial_port_data(port);
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
unsigned int cflag = termios->c_cflag;
int bps = tty_get_baud_rate(tty);
int quot;
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 6b7365632951..a46df73ee96e 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -307,7 +307,7 @@ static void belkin_sa_set_termios(struct tty_struct *tty,
unsigned long control_state;
int bad_flow_control;
speed_t baud;
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
iflag = termios->c_iflag;
cflag = termios->c_cflag;
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index b9cca6dcde07..9a564286bfd7 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -165,8 +165,8 @@ static int usb_console_setup(struct console *co, char *options)
}
if (serial->type->set_termios) {
- tty->termios->c_cflag = cflag;
- tty_termios_encode_baud_rate(tty->termios, baud, baud);
+ tty->termios.c_cflag = cflag;
+ tty_termios_encode_baud_rate(&tty->termios, baud, baud);
memset(&dummy, 0, sizeof(struct ktermios));
serial->type->set_termios(tty, port, &dummy);
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 1e71079ce33b..ba5e07e188a0 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -469,7 +469,7 @@ static void cp210x_get_termios(struct tty_struct *tty,
if (tty) {
cp210x_get_termios_port(tty->driver_data,
- &tty->termios->c_cflag, &baud);
+ &tty->termios.c_cflag, &baud);
tty_encode_baud_rate(tty, baud, baud);
}
@@ -631,7 +631,7 @@ static void cp210x_change_speed(struct tty_struct *tty,
{
u32 baud;
- baud = tty->termios->c_ospeed;
+ baud = tty->termios.c_ospeed;
/* This maps the requested rate to a rate valid on cp2102 or cp2103,
* or to an arbitrary rate in [1M,2M].
@@ -665,10 +665,10 @@ static void cp210x_set_termios(struct tty_struct *tty,
if (!tty)
return;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
old_cflag = old_termios->c_cflag;
- if (tty->termios->c_ospeed != old_termios->c_ospeed)
+ if (tty->termios.c_ospeed != old_termios->c_ospeed)
cp210x_change_speed(tty, port, old_termios);
/* If the number of data bits is to be updated */
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index b78c34eb5d3f..be34f153e566 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -922,38 +922,38 @@ static void cypress_set_termios(struct tty_struct *tty,
early enough */
if (!priv->termios_initialized) {
if (priv->chiptype == CT_EARTHMATE) {
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL |
+ tty->termios = tty_std_termios;
+ tty->termios.c_cflag = B4800 | CS8 | CREAD | HUPCL |
CLOCAL;
- tty->termios->c_ispeed = 4800;
- tty->termios->c_ospeed = 4800;
+ tty->termios.c_ispeed = 4800;
+ tty->termios.c_ospeed = 4800;
} else if (priv->chiptype == CT_CYPHIDCOM) {
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
+ tty->termios = tty_std_termios;
+ tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
CLOCAL;
- tty->termios->c_ispeed = 9600;
- tty->termios->c_ospeed = 9600;
+ tty->termios.c_ispeed = 9600;
+ tty->termios.c_ospeed = 9600;
} else if (priv->chiptype == CT_CA42V2) {
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
+ tty->termios = tty_std_termios;
+ tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
CLOCAL;
- tty->termios->c_ispeed = 9600;
- tty->termios->c_ospeed = 9600;
+ tty->termios.c_ispeed = 9600;
+ tty->termios.c_ospeed = 9600;
}
priv->termios_initialized = 1;
}
spin_unlock_irqrestore(&priv->lock, flags);
/* Unsupported features need clearing */
- tty->termios->c_cflag &= ~(CMSPAR|CRTSCTS);
+ tty->termios.c_cflag &= ~(CMSPAR|CRTSCTS);
- cflag = tty->termios->c_cflag;
- iflag = tty->termios->c_iflag;
+ cflag = tty->termios.c_cflag;
+ iflag = tty->termios.c_iflag;
/* check if there are new settings */
if (old_termios) {
spin_lock_irqsave(&priv->lock, flags);
- priv->tmp_termios = *(tty->termios);
+ priv->tmp_termios = tty->termios;
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -1021,7 +1021,7 @@ static void cypress_set_termios(struct tty_struct *tty,
"4800bps.");
/* define custom termios settings for NMEA protocol */
- tty->termios->c_iflag /* input modes - */
+ tty->termios.c_iflag /* input modes - */
&= ~(IGNBRK /* disable ignore break */
| BRKINT /* disable break causes interrupt */
| PARMRK /* disable mark parity errors */
@@ -1031,10 +1031,10 @@ static void cypress_set_termios(struct tty_struct *tty,
| ICRNL /* disable translate CR to NL */
| IXON); /* disable enable XON/XOFF flow control */
- tty->termios->c_oflag /* output modes */
+ tty->termios.c_oflag /* output modes */
&= ~OPOST; /* disable postprocess output char */
- tty->termios->c_lflag /* line discipline modes */
+ tty->termios.c_lflag /* line discipline modes */
&= ~(ECHO /* disable echo input characters */
| ECHONL /* disable echo new line */
| ICANON /* disable erase, kill, werase, and rprnt
@@ -1200,7 +1200,7 @@ static void cypress_read_int_callback(struct urb *urb)
/* hangup, as defined in acm.c... this might be a bad place for it
* though */
- if (tty && !(tty->termios->c_cflag & CLOCAL) &&
+ if (tty && !(tty->termios.c_cflag & CLOCAL) &&
!(priv->current_status & UART_CD)) {
dbg("%s - calling hangup", __func__);
tty_hangup(tty);
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index b5cd838093ef..afd9d2ec577b 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -687,8 +687,8 @@ static void digi_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
struct digi_port *priv = usb_get_serial_port_data(port);
- unsigned int iflag = tty->termios->c_iflag;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int iflag = tty->termios.c_iflag;
+ unsigned int cflag = tty->termios.c_cflag;
unsigned int old_iflag = old_termios->c_iflag;
unsigned int old_cflag = old_termios->c_cflag;
unsigned char buf[32];
@@ -709,7 +709,7 @@ static void digi_set_termios(struct tty_struct *tty,
/* don't set RTS if using hardware flow control */
/* and throttling input */
modem_signals = TIOCM_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
+ if (!(tty->termios.c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags))
modem_signals |= TIOCM_RTS;
digi_set_modem_signals(port, modem_signals, 1);
@@ -748,7 +748,7 @@ static void digi_set_termios(struct tty_struct *tty,
}
}
/* set parity */
- tty->termios->c_cflag &= ~CMSPAR;
+ tty->termios.c_cflag &= ~CMSPAR;
if ((cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD))) {
if (cflag&PARENB) {
@@ -1124,8 +1124,8 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
/* set termios settings */
if (tty) {
- not_termios.c_cflag = ~tty->termios->c_cflag;
- not_termios.c_iflag = ~tty->termios->c_iflag;
+ not_termios.c_cflag = ~tty->termios.c_cflag;
+ not_termios.c_iflag = ~tty->termios.c_iflag;
digi_set_termios(tty, port, &not_termios);
}
return 0;
@@ -1500,7 +1500,7 @@ static int digi_read_oob_callback(struct urb *urb)
rts = 0;
if (tty)
- rts = tty->termios->c_cflag & CRTSCTS;
+ rts = tty->termios.c_cflag & CRTSCTS;
if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
spin_lock(&priv->dp_port_lock);
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index cdf61dd07318..34e86383090a 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -87,7 +87,7 @@ static int empeg_startup(struct usb_serial *serial)
static void empeg_init_termios(struct tty_struct *tty)
{
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
/*
* The empeg-car player wants these particular tty settings.
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 499b15fd82f1..79451ee12ca0 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -173,10 +173,11 @@ static void f81232_set_termios(struct tty_struct *tty,
/* FIXME - Stubbed out for now */
/* Don't change anything if nothing has changed */
- if (!tty_termios_hw_change(tty->termios, old_termios))
+ if (!tty_termios_hw_change(&tty->termios, old_termios))
return;
/* Do the real work here... */
+ tty_termios_copy_hw(&tty->termios, old_termios);
}
static int f81232_tiocmget(struct tty_struct *tty)
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index f906b3aec217..0c8d1c226273 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -2102,7 +2102,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
{
struct usb_device *dev = port->serial->dev;
struct ftdi_private *priv = usb_get_serial_port_data(port);
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
unsigned int cflag = termios->c_cflag;
__u16 urb_value; /* will hold the new flags */
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index e1f5ccd1e8f8..f435575c4e6e 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -1458,7 +1458,7 @@ static void edge_throttle(struct tty_struct *tty)
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
edge_port->shadowMCR &= ~MCR_RTS;
status = send_cmd_write_uart_register(edge_port, MCR,
edge_port->shadowMCR);
@@ -1497,7 +1497,7 @@ static void edge_unthrottle(struct tty_struct *tty)
return;
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
edge_port->shadowMCR |= MCR_RTS;
send_cmd_write_uart_register(edge_port, MCR,
edge_port->shadowMCR);
@@ -1516,9 +1516,9 @@ static void edge_set_termios(struct tty_struct *tty,
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned int cflag;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
dbg("%s - clfag %08x iflag %08x", __func__,
- tty->termios->c_cflag, tty->termios->c_iflag);
+ tty->termios.c_cflag, tty->termios.c_iflag);
dbg("%s - old clfag %08x old iflag %08x", __func__,
old_termios->c_cflag, old_termios->c_iflag);
@@ -1987,7 +1987,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
tty = tty_port_tty_get(&edge_port->port->port);
if (tty) {
change_port_settings(tty,
- edge_port, tty->termios);
+ edge_port, &tty->termios);
tty_kref_put(tty);
}
@@ -2570,7 +2570,7 @@ static void change_port_settings(struct tty_struct *tty,
return;
}
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
switch (cflag & CSIZE) {
case CS5:
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 3936904c6419..765978ae752e 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -1870,7 +1870,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
/* set up the port settings */
if (tty)
- edge_set_termios(tty, port, tty->termios);
+ edge_set_termios(tty, port, &tty->termios);
/* open up the port */
@@ -2272,13 +2272,13 @@ static void change_port_settings(struct tty_struct *tty,
config = kmalloc (sizeof (*config), GFP_KERNEL);
if (!config) {
- *tty->termios = *old_termios;
+ tty->termios = *old_termios;
dev_err(&edge_port->port->dev, "%s - out of memory\n",
__func__);
return;
}
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
config->wFlags = 0;
@@ -2362,7 +2362,7 @@ static void change_port_settings(struct tty_struct *tty,
} else
dbg("%s - OUTBOUND XON/XOFF is disabled", __func__);
- tty->termios->c_cflag &= ~CMSPAR;
+ tty->termios.c_cflag &= ~CMSPAR;
/* Round the baud rate */
baud = tty_get_baud_rate(tty);
@@ -2408,10 +2408,10 @@ static void edge_set_termios(struct tty_struct *tty,
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned int cflag;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
dbg("%s - clfag %08x iflag %08x", __func__,
- tty->termios->c_cflag, tty->termios->c_iflag);
+ tty->termios.c_cflag, tty->termios.c_iflag);
dbg("%s - old clfag %08x old iflag %08x", __func__,
old_termios->c_cflag, old_termios->c_iflag);
dbg("%s - port %d", __func__, port->number);
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index fc09414c960f..5a96692b12a2 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -381,7 +381,7 @@ static void ir_set_termios(struct tty_struct *tty,
ir_xbof = ir_xbof_change(xbof) ;
/* Only speed changes are supported */
- tty_termios_copy_hw(tty->termios, old_termios);
+ tty_termios_copy_hw(&tty->termios, old_termios);
tty_encode_baud_rate(tty, baud, baud);
/*
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 22b1eb5040b7..bf3864045c18 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -921,7 +921,7 @@ static void iuu_set_termios(struct tty_struct *tty,
{
const u32 supported_mask = CMSPAR|PARENB|PARODD;
struct iuu_private *priv = usb_get_serial_port_data(port);
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = tty->termios.c_cflag;
int status;
u32 actual;
u32 parity;
@@ -930,7 +930,7 @@ static void iuu_set_termios(struct tty_struct *tty,
u32 newval = cflag & supported_mask;
/* Just use the ospeed. ispeed should be the same. */
- baud = tty->termios->c_ospeed;
+ baud = tty->termios.c_ospeed;
dbg("%s - enter c_ospeed or baud=%d", __func__, baud);
@@ -961,13 +961,13 @@ static void iuu_set_termios(struct tty_struct *tty,
* settings back over and then adjust them
*/
if (old_termios)
- tty_termios_copy_hw(tty->termios, old_termios);
+ tty_termios_copy_hw(&tty->termios, old_termios);
if (status != 0) /* Set failed - return old bits */
return;
/* Re-encode speed, parity and csize */
tty_encode_baud_rate(tty, baud, baud);
- tty->termios->c_cflag &= ~(supported_mask|CSIZE);
- tty->termios->c_cflag |= newval | csize;
+ tty->termios.c_cflag &= ~(supported_mask|CSIZE);
+ tty->termios.c_cflag |= newval | csize;
}
static void iuu_close(struct usb_serial_port *port)
@@ -993,14 +993,14 @@ static void iuu_close(struct usb_serial_port *port)
static void iuu_init_termios(struct tty_struct *tty)
{
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
+ tty->termios = tty_std_termios;
+ tty->termios.c_cflag = CLOCAL | CREAD | CS8 | B9600
| TIOCM_CTS | CSTOPB | PARENB;
- tty->termios->c_ispeed = 9600;
- tty->termios->c_ospeed = 9600;
- tty->termios->c_lflag = 0;
- tty->termios->c_oflag = 0;
- tty->termios->c_iflag = 0;
+ tty->termios.c_ispeed = 9600;
+ tty->termios.c_ospeed = 9600;
+ tty->termios.c_lflag = 0;
+ tty->termios.c_oflag = 0;
+ tty->termios.c_iflag = 0;
}
static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -1012,8 +1012,8 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port)
u32 actual;
struct iuu_private *priv = usb_get_serial_port_data(port);
- baud = tty->termios->c_ospeed;
- tty->termios->c_ispeed = baud;
+ baud = tty->termios.c_ospeed;
+ tty->termios.c_ispeed = baud;
/* Re-encode speed */
tty_encode_baud_rate(tty, baud, baud);
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index af0b70eaf032..7bcbb47e1449 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -158,7 +158,7 @@ static void keyspan_set_termios(struct tty_struct *tty,
p_priv = usb_get_serial_port_data(port);
d_details = p_priv->device_details;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
device_port = port->number - port->serial->minor;
/* Baud rate calculation takes baud rate as an integer
@@ -179,7 +179,7 @@ static void keyspan_set_termios(struct tty_struct *tty,
p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
/* Mark/Space not supported */
- tty->termios->c_cflag &= ~CMSPAR;
+ tty->termios.c_cflag &= ~CMSPAR;
keyspan_send_setup(port, 0);
}
@@ -1086,7 +1086,7 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
device_port = port->number - port->serial->minor;
if (tty) {
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
/* Baud rate calculation takes baud rate as an integer
so other rates can be generated if desired. */
baud_rate = tty_get_baud_rate(tty);
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index a4ac3cfeffc4..dcada8615fcf 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -338,7 +338,7 @@ static void keyspan_pda_set_termios(struct tty_struct *tty,
7[EOMS]1: 10 bit, b0/b7 is parity
7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?)
- HW flow control is dictated by the tty->termios->c_cflags & CRTSCTS
+ HW flow control is dictated by the tty->termios.c_cflags & CRTSCTS
bit.
For now, just do baud. */
@@ -353,7 +353,7 @@ static void keyspan_pda_set_termios(struct tty_struct *tty,
}
/* Only speed can change so copy the old h/w parameters
then encode the new speed */
- tty_termios_copy_hw(tty->termios, old_termios);
+ tty_termios_copy_hw(&tty->termios, old_termios);
tty_encode_baud_rate(tty, speed, speed);
}
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 5bed59cd5776..def9ad258715 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -311,12 +311,12 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
/* set up termios structure */
spin_lock_irqsave(&priv->lock, flags);
- priv->termios.c_iflag = tty->termios->c_iflag;
- priv->termios.c_oflag = tty->termios->c_oflag;
- priv->termios.c_cflag = tty->termios->c_cflag;
- priv->termios.c_lflag = tty->termios->c_lflag;
+ priv->termios.c_iflag = tty->termios.c_iflag;
+ priv->termios.c_oflag = tty->termios.c_oflag;
+ priv->termios.c_cflag = tty->termios.c_cflag;
+ priv->termios.c_lflag = tty->termios.c_lflag;
for (i = 0; i < NCCS; i++)
- priv->termios.c_cc[i] = tty->termios->c_cc[i];
+ priv->termios.c_cc[i] = tty->termios.c_cc[i];
priv->cfg.pktlen = cfg->pktlen;
priv->cfg.baudrate = cfg->baudrate;
priv->cfg.databits = cfg->databits;
@@ -445,9 +445,9 @@ static void klsi_105_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
struct klsi_105_private *priv = usb_get_serial_port_data(port);
- unsigned int iflag = tty->termios->c_iflag;
+ unsigned int iflag = tty->termios.c_iflag;
unsigned int old_iflag = old_termios->c_iflag;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = tty->termios.c_cflag;
unsigned int old_cflag = old_termios->c_cflag;
struct klsi_105_port_settings *cfg;
unsigned long flags;
@@ -560,7 +560,7 @@ static void klsi_105_set_termios(struct tty_struct *tty,
if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))
|| (cflag & CSTOPB) != (old_cflag & CSTOPB)) {
/* Not currently supported */
- tty->termios->c_cflag &= ~(PARENB|PARODD|CSTOPB);
+ tty->termios.c_cflag &= ~(PARENB|PARODD|CSTOPB);
#if 0
priv->last_lcr = 0;
@@ -587,7 +587,7 @@ static void klsi_105_set_termios(struct tty_struct *tty,
|| (iflag & IXON) != (old_iflag & IXON)
|| (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
/* Not currently supported */
- tty->termios->c_cflag &= ~CRTSCTS;
+ tty->termios.c_cflag &= ~CRTSCTS;
/* Drop DTR/RTS if no flow control otherwise assert */
#if 0
if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index fafeabb64c55..bf5c74965d34 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -191,11 +191,11 @@ static void kobil_release(struct usb_serial *serial)
static void kobil_init_termios(struct tty_struct *tty)
{
/* Default to echo off and other sane device settings */
- tty->termios->c_lflag = 0;
- tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
- tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
+ tty->termios.c_lflag = 0;
+ tty->termios.c_iflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
+ tty->termios.c_iflag |= IGNBRK | IGNPAR | IXOFF;
/* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */
- tty->termios->c_oflag &= ~ONLCR;
+ tty->termios.c_oflag &= ~ONLCR;
}
static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -581,14 +581,14 @@ static void kobil_set_termios(struct tty_struct *tty,
struct kobil_private *priv;
int result;
unsigned short urb_val = 0;
- int c_cflag = tty->termios->c_cflag;
+ int c_cflag = tty->termios.c_cflag;
speed_t speed;
priv = usb_get_serial_port_data(port);
if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID ||
priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
/* This device doesn't support ioctl calls */
- *tty->termios = *old;
+ tty_termios_copy_hw(&tty->termios, old);
return;
}
@@ -612,7 +612,7 @@ static void kobil_set_termios(struct tty_struct *tty,
urb_val |= SUSBCR_SPASB_EvenParity;
} else
urb_val |= SUSBCR_SPASB_NoParity;
- tty->termios->c_cflag &= ~CMSPAR;
+ tty->termios.c_cflag &= ~CMSPAR;
tty_encode_baud_rate(tty, speed, speed);
result = usb_control_msg(port->serial->dev,
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index a71fa0aa0406..df98cffdba65 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -454,7 +454,7 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
* either.
*/
spin_lock_irqsave(&priv->lock, flags);
- if (tty && (tty->termios->c_cflag & CBAUD))
+ if (tty && (tty->termios.c_cflag & CBAUD))
priv->control_state = TIOCM_DTR | TIOCM_RTS;
else
priv->control_state = 0;
@@ -634,7 +634,7 @@ static void mct_u232_set_termios(struct tty_struct *tty,
{
struct usb_serial *serial = port->serial;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
unsigned int cflag = termios->c_cflag;
unsigned int old_cflag = old_termios->c_cflag;
unsigned long flags;
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
index d47eb06fe463..2b0627b5fe2c 100644
--- a/drivers/usb/serial/metro-usb.c
+++ b/drivers/usb/serial/metro-usb.c
@@ -130,12 +130,6 @@ static void metrousb_read_int_callback(struct urb *urb)
/* Set the data read from the usb port into the serial port buffer. */
tty = tty_port_tty_get(&port->port);
- if (!tty) {
- dev_err(&port->dev, "%s - bad tty pointer - exiting\n",
- __func__);
- return;
- }
-
if (tty && urb->actual_length) {
/* Loop through the data copying each byte to the tty layer. */
tty_insert_flip_string(tty, data, urb->actual_length);
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index a07dd3c8cfef..012f67b2e4cc 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -1349,7 +1349,7 @@ static void mos7720_throttle(struct tty_struct *tty)
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
mos7720_port->shadowMCR &= ~UART_MCR_RTS;
write_mos_reg(port->serial, port->number - port->serial->minor,
MCR, mos7720_port->shadowMCR);
@@ -1383,7 +1383,7 @@ static void mos7720_unthrottle(struct tty_struct *tty)
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
mos7720_port->shadowMCR |= UART_MCR_RTS;
write_mos_reg(port->serial, port->number - port->serial->minor,
MCR, mos7720_port->shadowMCR);
@@ -1604,8 +1604,8 @@ static void change_port_settings(struct tty_struct *tty,
lStop = 0x00; /* 1 stop bit */
lParity = 0x00; /* No parity */
- cflag = tty->termios->c_cflag;
- iflag = tty->termios->c_iflag;
+ cflag = tty->termios.c_cflag;
+ iflag = tty->termios.c_iflag;
/* Change the number of bits */
switch (cflag & CSIZE) {
@@ -1753,11 +1753,11 @@ static void mos7720_set_termios(struct tty_struct *tty,
dbg("%s\n", "setting termios - ASPIRE");
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
dbg("%s - cflag %08x iflag %08x", __func__,
- tty->termios->c_cflag,
- RELEVANT_IFLAG(tty->termios->c_iflag));
+ tty->termios.c_cflag,
+ RELEVANT_IFLAG(tty->termios.c_iflag));
dbg("%s - old cflag %08x old iflag %08x", __func__,
old_termios->c_cflag,
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 2f6da1e89bfa..402c32d7accb 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1651,7 +1651,7 @@ static void mos7840_throttle(struct tty_struct *tty)
return;
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
mos7840_port->shadowMCR &= ~MCR_RTS;
status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
mos7840_port->shadowMCR);
@@ -1694,7 +1694,7 @@ static void mos7840_unthrottle(struct tty_struct *tty)
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
mos7840_port->shadowMCR |= MCR_RTS;
status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
mos7840_port->shadowMCR);
@@ -2000,8 +2000,8 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
lStop = LCR_STOP_1;
lParity = LCR_PAR_NONE;
- cflag = tty->termios->c_cflag;
- iflag = tty->termios->c_iflag;
+ cflag = tty->termios.c_cflag;
+ iflag = tty->termios.c_iflag;
/* Change the number of bits */
if (cflag & CSIZE) {
@@ -2161,10 +2161,10 @@ static void mos7840_set_termios(struct tty_struct *tty,
dbg("%s", "setting termios - ");
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
dbg("%s - clfag %08x iflag %08x", __func__,
- tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag));
+ tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag));
dbg("%s - old clfag %08x old iflag %08x", __func__,
old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
dbg("%s - port %d", __func__, port->number);
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 5976b65ab6ee..9f555560bfbf 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -404,10 +404,10 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty)
static void oti6858_init_termios(struct tty_struct *tty)
{
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
- tty->termios->c_ispeed = 38400;
- tty->termios->c_ospeed = 38400;
+ tty->termios = tty_std_termios;
+ tty->termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
+ tty->termios.c_ispeed = 38400;
+ tty->termios.c_ospeed = 38400;
}
static void oti6858_set_termios(struct tty_struct *tty,
@@ -425,7 +425,7 @@ static void oti6858_set_termios(struct tty_struct *tty,
return;
}
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
spin_lock_irqsave(&priv->lock, flags);
divisor = priv->pending_setup.divisor;
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 13b8dd6481f5..2b9108a8ea64 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -260,16 +260,16 @@ static void pl2303_set_termios(struct tty_struct *tty,
serial settings even to the same values as before. Thus
we actually need to filter in this specific case */
- if (!tty_termios_hw_change(tty->termios, old_termios))
+ if (!tty_termios_hw_change(&tty->termios, old_termios))
return;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
buf = kzalloc(7, GFP_KERNEL);
if (!buf) {
dev_err(&port->dev, "%s - out of memory.\n", __func__);
/* Report back no change occurred */
- *tty->termios = *old_termios;
+ tty->termios = *old_termios;
return;
}
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index 151670b6b72a..7df9cdb053ed 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -275,7 +275,7 @@ static void qt2_set_termios(struct tty_struct *tty,
{
struct usb_device *dev = port->serial->dev;
struct qt2_port_private *port_priv;
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
u16 baud;
unsigned int cflag = termios->c_cflag;
u16 new_lcr = 0;
@@ -406,7 +406,7 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
port_priv->device_port = (u8) device_port;
if (tty)
- qt2_set_termios(tty, port, tty->termios);
+ qt2_set_termios(tty, port, &tty->termios);
return 0;
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 0274710cced5..b14ebbd73567 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -382,7 +382,7 @@ static int sierra_send_setup(struct usb_serial_port *port)
static void sierra_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
- tty_termios_copy_hw(tty->termios, old_termios);
+ tty_termios_copy_hw(&tty->termios, old_termios);
sierra_send_setup(port);
}
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index cad608984710..ab68a4d74d61 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -316,10 +316,10 @@ static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on)
static void spcp8x5_init_termios(struct tty_struct *tty)
{
/* for the 1st time call this function */
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
- tty->termios->c_ispeed = 115200;
- tty->termios->c_ospeed = 115200;
+ tty->termios = tty_std_termios;
+ tty->termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
+ tty->termios.c_ispeed = 115200;
+ tty->termios.c_ospeed = 115200;
}
/* set the serial param for transfer. we should check if we really need to
@@ -330,7 +330,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
struct usb_serial *serial = port->serial;
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = tty->termios.c_cflag;
unsigned int old_cflag = old_termios->c_cflag;
unsigned short uartdata;
unsigned char buf[2] = {0, 0};
@@ -340,7 +340,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
/* check that they really want us to change something */
- if (!tty_termios_hw_change(tty->termios, old_termios))
+ if (!tty_termios_hw_change(&tty->termios, old_termios))
return;
/* set DTR/RTS active */
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index 3fee23bf0c14..cf2d30cf7588 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -216,7 +216,7 @@ static void ssu100_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
struct usb_device *dev = port->serial->dev;
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
u16 baud, divisor, remainder;
unsigned int cflag = termios->c_cflag;
u16 urb_value = 0; /* will hold the new flags */
@@ -322,7 +322,7 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
dbg("%s - set uart failed", __func__);
if (tty)
- ssu100_set_termios(tty, port, tty->termios);
+ ssu100_set_termios(tty, port, &tty->termios);
return usb_serial_generic_open(tty, port);
}
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index a4404f5ad68e..f502a16aac21 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -520,7 +520,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
}
if (tty)
- ti_set_termios(tty, port, tty->termios);
+ ti_set_termios(tty, port, &tty->termios);
dbg("%s - sending TI_OPEN_PORT", __func__);
status = ti_command_out_sync(tdev, TI_OPEN_PORT,
@@ -562,7 +562,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
usb_clear_halt(dev, port->read_urb->pipe);
if (tty)
- ti_set_termios(tty, port, tty->termios);
+ ti_set_termios(tty, port, &tty->termios);
dbg("%s - sending TI_OPEN_PORT (2)", __func__);
status = ti_command_out_sync(tdev, TI_OPEN_PORT,
@@ -831,8 +831,8 @@ static void ti_set_termios(struct tty_struct *tty,
int port_number = port->number - port->serial->minor;
unsigned int mcr;
- cflag = tty->termios->c_cflag;
- iflag = tty->termios->c_iflag;
+ cflag = tty->termios.c_cflag;
+ iflag = tty->termios.c_iflag;
dbg("%s - cflag %08x, iflag %08x", __func__, cflag, iflag);
dbg("%s - old clfag %08x, old iflag %08x", __func__,
@@ -871,7 +871,7 @@ static void ti_set_termios(struct tty_struct *tty,
}
/* CMSPAR isn't supported by this driver */
- tty->termios->c_cflag &= ~CMSPAR;
+ tty->termios.c_cflag &= ~CMSPAR;
if (cflag & PARENB) {
if (cflag & PARODD) {
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 27483f91a4a3..aa4b0d775992 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -207,7 +207,7 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
if (retval)
goto error_get_interface;
- retval = tty_standard_install(driver, tty);
+ retval = tty_port_install(&port->port, driver, tty);
if (retval)
goto error_init_termios;
@@ -305,8 +305,7 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
* Do the resource freeing and refcount dropping for the port.
* Avoid freeing the console.
*
- * Called asynchronously after the last tty kref is dropped,
- * and the tty layer has already done the tty_shutdown(tty);
+ * Called asynchronously after the last tty kref is dropped.
*/
static void serial_cleanup(struct tty_struct *tty)
{
@@ -423,7 +422,7 @@ static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
if (port->serial->type->set_termios)
port->serial->type->set_termios(tty, port, old);
else
- tty_termios_copy_hw(tty->termios, old);
+ tty_termios_copy_hw(&tty->termios, old);
}
static int serial_break(struct tty_struct *tty, int break_state)
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 6855d5ed0331..72b678d90831 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -67,7 +67,7 @@ void usb_wwan_set_termios(struct tty_struct *tty,
struct usb_wwan_intf_private *intfdata = port->serial->private;
/* Doesn't support option setting */
- tty_termios_copy_hw(tty->termios, old_termios);
+ tty_termios_copy_hw(&tty->termios, old_termios);
if (intfdata->send_setup)
intfdata->send_setup(port);
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 473635e7f5db..b36077de72b9 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -724,7 +724,7 @@ static void firm_setup_port(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct whiteheat_port_settings port_settings;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = tty->termios.c_cflag;
port_settings.port = port->number + 1;
diff --git a/firmware/Makefile b/firmware/Makefile
index 344713b11669..fdc9ff045ef8 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -40,7 +40,6 @@ fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-6.2.1a.fw \
bnx2/bnx2-mips-06-6.2.1.fw \
bnx2/bnx2-rv2p-06-6.0.15.fw
fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin
-fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin
fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \
cxgb3/t3c_psram-1.1.0.bin \
cxgb3/t3fw-7.10.0.bin \
diff --git a/firmware/intelliport2.bin.ihex b/firmware/intelliport2.bin.ihex
deleted file mode 100644
index e9cfe8cb2b21..000000000000
--- a/firmware/intelliport2.bin.ihex
+++ /dev/null
@@ -1,2147 +0,0 @@
-:100000003C4237180201030000000000000000001D
-:10001000576564204465632030312031323A3234F0
-:100020003A33302031393939000000000000000037
-:10003000E96C0F426547694E6E496E47206F462056
-:10004000634F6445CC135A15E8167618041A921BB0
-:10005000201DAE1E3C20CA215823E6247426022807
-:1000600090291E2BAC2C3A2EC82F5631E432723414
-:1000700000368E371C39AA3A383CC63D543FE24020
-:100080007042FE438C451A47A848364AC44B524D2D
-:10009000E04E6E50FC518A531855A6563458C2593A
-:1000A000505BDE5C6C5EFA5F88611663A464326646
-:1000B000C0674E69DC6A6A6CF86D866F1471A27253
-:1000C0003074BE754C776C778C77AC7733DB8ADC19
-:1000D0005333DB250700750A8A1E080183E30CEB06
-:1000E00020903C01750A8A1E080180E3C0EB129043
-:1000F0008A1E0D013C02750680E30CEB049080E340
-:10010000C053508B1EBA138EDBE86A65558BEC53D7
-:100110001E2BC08ED88B5E04C1E304035E06D1E3C0
-:100120002E8B9F44008D472A1E5A1F5B5DC3558B43
-:10013000EC531E2BC08ED88B5E04C1E304035E0615
-:10014000D1E32E8B9F44008D47341E5A1F5B5DC345
-:10015000FB558BEC53515256571E061E0733C08E6B
-:10016000D88B5E04268A47592503008BF0D1E62EF2
-:100170008BB4C400C1E0042602471AD1E08BE82EFC
-:100180008BAE4400892C268A471C88440F268A4758
-:100190001D884410268A471E884411268A471F88D6
-:1001A0004412268A4720884413268A472388441409
-:1001B000268A4724884415268A475A88440E33C025
-:1001C00089440689440888440B88440AB021B464F1
-:1001D000894404894402B05588440D88440CE86A77
-:1001E00000725BE8C900E8C110894408807C0F01F7
-:1001F0007429E82B02E87F02807C0F03741DE8A9B4
-:10020000108BF82B44083DA00F7210897C0833C076
-:1002100087440685C07504C6440AFF8A440A84C020
-:10022000750BB80800E86A4AE8A90173BFE84F01F6
-:100230008166487FFF83667ABFB002E8040E8A4475
-:100240000A98071F5F5E5A595B5DC3814E48800064
-:10025000B040E83D4AE88940732AE84D108BD8B099
-:1002600005E82E4AF6462702751AE83D102BC33DD5
-:10027000581B72EB8166487FFFB002E8C40DC6448C
-:100280000A01F9C3834E7A40F8C3FBB001E8024A81
-:10029000FAE8991EE40A84C075F0B04EE60AFBB095
-:1002A00001E8EE49FAE8851EE40A84C075F0C3FA55
-:1002B000E87A1EE4EC884416E4E4884417E4F888FD
-:1002C0004418E4F0884419E41088441AE41288447D
-:1002D0001BE41488441CE43488441DE43688441E1E
-:1002E000E4D824018AE0E4DA24020AC488441F8A9C
-:1002F0004410E8CD1F8A4411E835218A4412E88968
-:10030000218A4413E84321C686A10000E414241086
-:10031000E614E412243DE6128A44153C01721E776D
-:1003200016B011E634B013E636E4140C10E614E40B
-:10033000120C40E612EB06E4120C02E6128A440F9D
-:100340003C0174063C02740AEB0EE4120C08E6123F
-:10035000EB06E4120C10E612E82FFF8A44143C026C
-:100360007508B05588440C88440DB021B4648944A4
-:1003700004894402E40C0C10E60CE8ED39FBC3E8F8
-:100380005F3F7308FBB00AE80849EBF3FAE89D1DEC
-:100390008A64168A441789869400E6E48AC4E6ECE7
-:1003A0008A64188A441989869600E6F08AC4E6F8B9
-:1003B0008A441AE6108A441BE6128A441CE6148A10
-:1003C000441DE6348A441EE6368A441FE6D8E6DA3F
-:1003D000E9B7FE90FA8A440EE6FEE402A80175052C
-:1003E00033C0FBF8C333C0E400FBF9C38A64148054
-:1003F000FC02742BFEC0FEC780FF4E721C74098085
-:10040000FF507308B00AEB17B00DEB1302DC32FF9C
-:1004100080FB7F7C02B3218AC33C7F7C02B021C376
-:10042000FA807C0B047602FBC38B46243D080072E5
-:10043000F68E46028B7E228A440C8B5C02AAE8ABC5
-:10044000FFAAE8A7FFAAE8A3FFAAE89FFF88440C39
-:10045000895C0280440B04897E22836E24048346D7
-:100460001A04807E26027406806626FDFBC360B0F7
-:10047000FDE8023F61FBC3FA807C0F037509C644A7
-:100480000B00E8E538FBC3C47E148B4E3A85C97572
-:1004900035268B0D4747E3EA3B7E047622B80200FF
-:1004A00039462E7707C7462E0000EB138B5E2C894A
-:1004B0005E0426C70700004343895E2C29462E852B
-:1004C000C978CE894E3A8A440D8B5C04268A25472A
-:1004D0003AC47516FE4C0BFF4406E80FFFE2ED88A8
-:1004E000440D895C04894E3AEBA7C6440AFEE879BC
-:1004F00038FBC390E8B30D8AE88A0ECB13B3078AA2
-:10050000C1EEEB00EC3AC1750902CDFECB75F0EB04
-:100510000C90880ECB138AE8BBFFFFF9C3880ECB83
-:1005200013F8C390BB3F3F8A8E9E00BAFE00EC8A50
-:10053000E832C122C37502F8C3F9C390E8E5FF733E
-:1005400001C3BAD000BB03038A8E9F00EC8AE83255
-:10055000C122C37502F8C3F9C39033C08ED88EC0D0
-:10056000803EC813007507B00AE82647EBF2FB335C
-:10057000DB8A1EC913434383FB7E760733DBB0025D
-:10058000E80F472E8BAF4400837E080074E7881E77
-:10059000C913B002E8FB46FAF7463840007414E885
-:1005A000961BE87FFF721C33D28A969F0083C20E8F
-:1005B000EB0C90E8771BE883FF7208BA4800E83339
-:1005C000FF73AB23CB898E9A0089969C00FE86B57B
-:1005D00000C606C81300B00AE8670AFBEB891018CA
-:1005E000082833C0A005018AC824407524C7067CAA
-:1005F000128E45C70642120100C606541202B00808
-:10060000F6C1017402B004A34612A24C12A29412C5
-:10061000C3C7067C12B645A00F0184C0750E6A00E0
-:100620001FC60693121E9C0EE8B10C90C70644121A
-:100630000100A342128BD8C1E304881E9412BEE2CB
-:10064000052BF08BC833DB8BFB2EAC888548128AD8
-:10065000D80C05E6FE8AE0EB00E4FE32C4A83F7445
-:1006600003E99E00E400888550128AE02430BA1025
-:10067000FF3C30741280FC04740ABA0403F60608C6
-:1006800001FE7403BA080F88954C1202FA32C0F6C4
-:10069000C4087402B001888558128AC43C35745B62
-:1006A0003C3674573C3474533C04744F3C14744BC4
-:1006B0003C157447A8407425C685541204D1E7B48C
-:1006C000038AC389855C128AC38AE380CC01898549
-:1006D0006412D1EF47E203EB1A90E96CFFC6855430
-:1006E0001202D1E78AE68AC30C0489855C12D1EF35
-:1006F00047E2E733C08AC7A34612C3C68554120631
-:10070000EBBBC68554120033C08885501288854CD7
-:100710001288855812EBA6C7462602128B461E8900
-:1007200046008946228B4620894624C7461A000087
-:10073000C3C7463C8000C7463801001E568B763042
-:100740008976048976148E5E0633C089044646890C
-:10075000762C89463A8B4632484889462E5E1FC31E
-:1007600033C089464889464AC74646AE0189464E47
-:100770008B46448946508B4642894640894608C389
-:1007800033C0894676894678C7467A1000561E8B54
-:10079000767089761089760C8E5E12C70400008B05
-:1007A00046728946741F5EC3895618895602895657
-:1007B0000689560A89560E8956128956168BD84BC9
-:1007C0004BC1E302BF0200897E1E03FB897E30031A
-:1007D000FB897E4203FB897E7083EB08895E20895A
-:1007E0005E32895E44895E7250E82BFFE871FFE853
-:1007F0003FFFE88BFF58C3B83075C1E8040E5B03B8
-:10080000C3A3BA13833E4212007407803E941200C1
-:10081000750E6A001FC60693121E9C0EE8BD0A9054
-:10082000B8307AC1E80440A3C0132B061201F7D8F0
-:1008300033D28BCA8A0E9412F7F13D8000770E6A8C
-:10084000001FC6069312259C0EE8900A90483DFFB3
-:10085000077203B8FF07A3C21333C98A0E94123379
-:10086000F6B800092E8BAC440089464C404646E25F
-:10087000F38A0E941233F68B16C013A1C2132E8B7B
-:10088000AC4400E822FF03D04646E2F2C333C02E58
-:100890008BAD44008946084747E2F4C35133C00A90
-:1008A000C22E8BAD440089869E00814E38002047C1
-:1008B00047FEC480FC04720432E4FEC0E2E35983C4
-:1008C000E9107405F7D9E8C4FFC35133C00AC22E3A
-:1008D0008BAD440089869E00834E3840474780C4D4
-:1008E00010790432E4FEC0E2E65983E9107405F79A
-:1008F000D9E899FFC3E8D2FFC38D089C08CA08F560
-:10090000088B0E421233F6515633DB8BCB8A944858
-:10091000128A8C4C128A9C54128BFEC1E70585DB2F
-:100920007502B1102EFF97F9085E5946E2D9C3014E
-:10093000CC03D000E802D000E801D000E800D000ED
-:10094000E804D0A8DA00DC00DE01D803CC03CC0335
-:10095000CC04D0A8DA20DC00DE03CC03CC03CC002E
-:10096000D803CC03CC03CC03CC03CC03CC03CC0303
-:10097000CC03CC03CC03CC03CC03CC03CC03CC03FF
-:10098000CC04D000DA20DC03DE01D803CC03CC0396
-:10099000CC03CC00D800CC00D0000056521E0E1F55
-:1009A000BE2F0933D2FCAD85C0740D8AD4EEAD855F
-:1009B000C074058AD4EEEBEE1F5A5EC3E48084C097
-:1009C00074167814B027E6FCB011E634E4FC3C273A
-:1009D0007506E4117502F8C3F9C383C206B0BFEE11
-:1009E00083EA02B010EE8886AF00B01183C204EE35
-:1009F00083C202EEB01383C202EE83C202EE2EA1C6
-:100A00004C2D8986940083EA0EEE83C2028AC4EEDE
-:100A100083C204B003EE8886A80083EA0432C0EEE5
-:100A200083C202B089EE8886A6000C06EEB040B400
-:100A30003889461CC74636380083C20432C0EE8867
-:100A400086A700C383C206B0BFEE83EA02EC3A86F3
-:100A5000AF00752483C204EC3C11751C83C206EC04
-:100A60003C13751483EA088A86A800EE83EA02EC38
-:100A700024C03CC07502F8C3F9C333C98BD18BF1D4
-:100A80008A0E9412C1E9022E8BAC4400F74638005E
-:100A900020740E8A869E00E6FE32C0E68042E8FAA6
-:100AA000FE83C608E2E185D27403E80508C333C9B2
-:100AB0008BF18A0E94122E8BAC4400F7463840001E
-:100AC0007406E87316E812FF4646E2EAC333C98BA0
-:100AD000F18A0E9412C1E9022E8BAC4400F746381D
-:100AE00000207416E84616E8D2FE730E6A001FC690
-:100AF0000693121C9C0EE8E3079083C608E2D9C354
-:100B000033C98BF18A0E94122E8BAC4400F7463811
-:100B100040007416E82116E82AFF730E6A001FC60B
-:100B20000693121C9C0EE8B307904646E2DAC30C0B
-:100B300000001000131200001400283C001B3E00AF
-:100B4000002A00002C0000420014D80000DA000047
-:100B50003400113600133800113A001300005650CB
-:100B600052BE2F0B2EAD85C07406922EACEEEBF468
-:100B70005A585EC3532EA16022E6E4E6F08AC4E62A
-:100B8000ECE6F8E8D8FFB04BE610B050E612B0380B
-:100B9000E614E8AE15B046E60AE8A715B01AE60A6C
-:100BA000E8A015B022E60AE89915E8FD068BD8E41E
-:100BB00016A8047518E8F2062BC33D320072F06ADD
-:100BC000001FC6069312239C0EE8100790E8DA0671
-:100BD0002BC33D2400771BB031E6FC565155B910AC
-:100BE000002E8BAC4400814E3880004646E2F25D18
-:100BF000595EE869FFE84B15B046E60AE844155B24
-:100C0000C333F68B0E42122E8BAC4400F7463800ED
-:100C1000207406E81715E85BFF83C620E2E9C38B62
-:100C2000C20504008946282EA14C2D89868E008994
-:100C300086900089869200C686A3000AC686C300F5
-:100C4000035283C2048A86A6000C06EE5A83C202AF
-:100C5000B005EE8886A500C3E803FFE8E514B042BE
-:100C6000E60AF74638800074062EA19C22EB042E7B
-:100C7000A16C22C7461C0C008986940089869600C8
-:100C800089868E008986900089869200E6F0E6E4E7
-:100C90008AC4E6F8E6ECC686C30003E8A514B01AD9
-:100CA000E60AB0108886A500E60CC333C98BF18A2A
-:100CB0000E94122E8BAC4400F7463840007406E8C0
-:100CC0007614E85AFF4646E2EAC333C98BF18A0E2E
-:100CD00094122E8BAC4400F7463800207406E84C82
-:100CE00014E874FF4646E2EAC390833E441200755E
-:100CF00014B001BA0601EE2AC0EEB002EEB004EE66
-:100D0000B80002EB0FBA0601B040EEB801008A0E3F
-:100D10000E01D3E0A38812C3A18812A384122D2050
-:100D200000A38A122D2000A38212C706861220007B
-:100D3000C70680123200C3833E44120074768B0EC5
-:100D4000421233F68AA4541284E4745F8A844812EF
-:100D50000C04E6FEF6C4047425B01BBA0000EEEBEA
-:100D6000002AC0BA0200EEEB00B003EEEB0032C086
-:100D7000BA0200EEEB00BA0000B000EEEB2DB01F9F
-:100D8000BA0000EEEB002AC0BA0200EEEB00B0039E
-:100D9000EEEB00D1E68A845D12D1EEF6D0BA020005
-:100DA000EEEB00BA0000B00AEEEB00E404EB00E466
-:100DB0000446E290C390B81400BA3EFFEFB80600B4
-:100DC000BA32FFEFB80F00BA34FFEFBA36FFEF8345
-:100DD0003E4412007516B81100BA38FFEFB8120081
-:100DE000BA3AFFEFB81B00BA3CFFEFC3B81100BA24
-:100DF00038FFEFB81200BA3AFFEFB81B00BA3CFF59
-:100E0000EFC3B8FC00BA28FFEFFB833E4412007426
-:100E100007B8CC00BA28FFEFC300FFFF202428FF4B
-:100E20002CFFFF303438FFFF3C903C0F770EBB198E
-:100E30000E2ED73CFF74058AD8F8C3902ADBF9C37D
-:100E4000833E4412007427A00601802606013080EC
-:100E50003E0601307518B90200BFC413BA0601EC92
-:100E6000A82075F8BA0401EDABE2F1EB1690B904D5
-:100E700000BFC413BA0601ECA82075F8BA0401EC4F
-:100E8000AAE2F1FA90BEC413AD80E43F80FC027484
-:100E90000E6A001FC60693120A9C0EE83E0490AD2F
-:100EA0003C0F75ED8AC4E881FF72E6881E1A01C600
-:100EB000068E1200B0000A061A01BA0001EEC6063C
-:100EC0008F1240833E4412007506B80C00EB04906C
-:100ED000B84C00BA28FFEFC3833E4412007501C32B
-:100EE000A150120B0652120AC4A80874F2A00F01F6
-:100EF0002AE450FF36BA131FE8505683C4026A0032
-:100F00001F33C0A3BC13A00F01A3BE138B1EBC13C1
-:100F10008A875012F687501208740D24078AE0BEA3
-:100F2000CC00A0BC13E8943DFF06BC13FF0EBE131B
-:100F300075DAC3901E33C08ED8B001E8543D1FC38C
-:100F400033C98BF18A0E94122E8BAC4400C74662D3
-:100F50003844C7467CFC3BC7467EE23BC7868000E0
-:100F6000EC3CE8AB16C686C00011837E080074070F
-:100F70005156E833335E594646E2CDC333C98BF14F
-:100F80008BF98A0E9412C1E902E3132E8BAC440054
-:100F90008A869E0088856C1283C60847E2EDC3FAF4
-:100FA000FCB0C0BA0001EE33C08ED88EC08ED0BF68
-:100FB0001601B9CC772BCFD1E9F3ABBC4012E8D9FD
-:100FC00002E8703CBECC0FE8F23CF49033C08ED8FF
-:100FD0008EC08ED0F6060A0180740BBE3555E8DB54
-:100FE0003CB001E8AC3CE8B300E8F6F5E808F8E806
-:100FF0000FF9E885FAE8B6FAE8EFFCE8C210E80372
-:101000003CE8B2FDE830FDE85402C6068F12C0E8A5
-:10101000BBFAE8EBFAE8E9FBE8AFFCE88DFCE81F77
-:10102000FFE858FFE8DBFDE816FE33C0BE5A05E8CE
-:101030008A3CE8A3FEE8E0FCFBBEA444E87D3CE972
-:10104000CA2D56988BF08B425285C07527C74252E5
-:10105000010053368B9C2C01F6C301750C36896850
-:10106000523689AC2C015B5EC33689AC2C013689C3
-:10107000AC1C015B5EC356988BF033ED368B841C41
-:1010800001A80175158BE833C08742523689841C4C
-:1010900001A80174053689842C015EC3565133F6CC
-:1010A000B80100B9080089841C0189842C014646D6
-:1010B000E2F4595EC390BB01008BE8FF4E6E740AE8
-:1010C0008BDD8B4658A80174F0C38B4648A90800F5
-:1010D0007445F7463840007427E85C1080C2068AE1
-:1010E00086A80024BF8886A800EE60B0FEE886329D
-:1010F00061B002E84CFF8B464824F7894648EB175D
-:10110000E82A10814E2600408A86A5000C028886B7
-:10111000A500E60C8B4648A904007414B002E8212F
-:10112000FF8B464824FB89464860B0DFE8473261C0
-:1011300033C0874658F6C301750B36894758A80156
-:10114000750DE974FFA32201A8017503E96AFF89FF
-:101150001E3201C3BB01008BE8F74638400074150E
-:10116000E8D50F80C20AECA840750A8BDD8B465685
-:10117000A80174E3C38B462680E4FE80CC02894636
-:1011800026B002E8BCFE33C0874656F6C301750A96
-:1011900036894756A801750BEBBDA32001A8017540
-:1011A00002EBB4891E3001C3601E062BC08ED8A08E
-:1011B000901284C07549A12201A8017503E8F6FECA
-:1011C000A12001A8017503E88AFFA1AC13487805A6
-:1011D0007445A3AC13A1AE134878057451A3AE13A4
-:1011E000A1B0134878057463A3B013A17E124078B0
-:1011F00003A37E12B80080BA22FFEF071F61CFA0C1
-:101200009112403C02720B33C0A29112FF167C1265
-:10121000EBA4A29112EB9FA08E1232068F12A28E27
-:10122000120A061A01BA0001EEB82C01EBA4833EA3
-:101230008412107211BA28FFED0C81EFE85337BA0F
-:1012400028FFED247EEFB80400EB92C6068D120154
-:10125000E83F37C6068D1200A1B213EB8B908A1EB1
-:101260000B012AFF6BC319BA62FFEFB80A00BA601C
-:10127000FFEFB801E0BA66FFEFB8FFFFBA52FFEF29
-:10128000B809C0BA56FFEFC706AC132C01C706AEAB
-:10129000130400C606911200C3908A1E0B012AFF98
-:1012A0006BC305D1E8A31801C39052BA50FFED5AA1
-:1012B000C39053518B1E1801B9320590E2FE4B7555
-:1012C000F7595BC3B080BA00010A061A01EEC39059
-:1012D000B040EBF2B0C0EBEEB000EBEAFA60061EF5
-:1012E000162BDB8EDB2EA1BA4C2EA3924CA09312B0
-:1012F000988BE889262D7A803ECA13007403E96B27
-:1013000042E8C0FFE8ABFFE8A8FFB020C606901295
-:1013100000FF167C128BFD83FF0A7211E8B9FFE80B
-:1013200090FFE8ABFFE88AFF83EF0AEBEA0BFF745C
-:101330000FE8A4FFE87BFFE89AFFE875FF4F75F11F
-:10134000E895FFE86CFFEBB98A86A50024FDEE88DE
-:1013500086A500C38A86A6000C02EEC38B7638F7FA
-:10136000C6010074EF8B4E368B462E3BC173028B49
-:10137000C82BC189462E014E34C47E0426010D8B34
-:101380007E2C83EA04F36C8EC1897E2C3B463C7232
-:1013900012F7C62000750B83CE20897638B000E89E
-:1013A000A0FCC3F7C60400741B8BD883CE108976CB
-:1013B000388A86A70024FE8886A70083C208EE83A9
-:1013C000EA088BC33D40007201C3814E380004839C
-:1013D000C2028A86A50024FA8886A500EEC38A8602
-:1013E000A6000C02EEC3F74638010074F18B4E2EB6
-:1013F00032DB8ABEA30083C206C476048B7E2C83B4
-:10140000F908722CECA80174168AE083EA0AEC83CE
-:10141000C20A84E77551AAFEC34983F90873E5320D
-:10142000FF26011C015E34897604894E2E897E2CAC
-:101430003B4E3C7211F64638207401C3834E38206F
-:10144000B000E8FDFBC3F64638047415834E38102F
-:101450008A86A70024FE8886A70083EA02EE83C25C
-:10146000023D4000725DC332FF26031C85DB740918
-:1014700026891C8BF74747494980E41E80CCC0264B
-:101480008904F6C41074278B7638F7C60010740BE5
-:1014900050FE86B200B00AE8A8FB58F7C6000174F7
-:1014A0000DE882268B76388B4E2E8B7E04AB8BF725
-:1014B00033C0AB32DB8ABEA300494983F9087217F7
-:1014C000E941FF814E38000483C2F88A86A50024D2
-:1014D000FA8886A500EEC3E945FF83C208EC88863A
-:1014E000AA00C0E8048AE08AC88686A90032E08B98
-:1014F0005E3E84E3744F8AC18B4E26F6C504740C9D
-:10150000A808740580E1BFEB0380C940F6C50874E4
-:101510000CA802740580E17FEB0380C980884E2609
-:101520008BF08A86A50084C97408A802741524FD6E
-:10153000EB06A802750D0C028886A50083EA0AEE68
-:1015400083C20A8BC684E77501C3C686BA0001B0A0
-:101550000EE8EEFAF74638000274EE837E2E06722D
-:10156000E88AA6AA00C45E048B7E2CB0FFAAB00253
-:10157000AB26830703836E2E03897E2CF646382024
-:101580007401C3834E3820B000E8B6FAC39083EAF2
-:1015900008E9B4FD83C2068B5E26F6C3C075EF8BE7
-:1015A0004E1CEC8886A40083EA0AA82075028ACD26
-:1015B00032ED8B461A3BC87318014E2A2BC189465F
-:1015C0001AC57600F36E8ED98976003D2000723000
-:1015D000C385C074318BC801462AC57600F36E8E70
-:1015E000D980CB02895E26E832F1F6C701751683F1
-:1015F000C202E853FDF6C710750BB002E843FAC308
-:10160000F6C70174F0C380CB02895E26F6C7017469
-:10161000DE83C202E831FDF686A40040740B80E749
-:10162000FE80CF02895E26EBCCB004E814FAC3C07A
-:10163000C2C8CAC4C6CCCED0D2D8DAD4D6DCDE90EA
-:10164000E90E01E4C48AE0E4C48BD083F90872F0A7
-:1016500026833F0074048BDF49498BFB8ADE83E3DA
-:101660000F2E8AA72F16ABF6C4107424F7C60010ED
-:10167000740B50FE86B200B00AE8C6F958F7C600EF
-:1016800001740DE8A0248B76388B4E2E8B7E04AB34
-:10169000897E0433C0AB4949894E2E897E2C8BC18B
-:1016A000EB4E90EB9E90E4D684C07963E6D08AC876
-:1016B00025030003D8D1E32E8BAF4400888EAE0003
-:1016C0008B4E2EC45E048B7E2C8B7638E4862407EA
-:1016D0003C0375CFE41C913BC173028BC82BC189BD
-:1016E000462E014E3426010FBAC400F36C897E2CBD
-:1016F0003B463C721CF7C62000750B83CE208976D2
-:1017000038B000E83CF98A86AE00243FE6D6C3F93B
-:10171000C3F7C60A007435F7C61000752F83CE10C4
-:10172000897638F7C60200740E50E4D824FEE6D855
-:1017300058F7C6080074155051B9E803E40A84C08C
-:10174000E0FA84C07504B024E60A59583D4000739D
-:10175000B58A86A50024EF8886A500E60C81CE1008
-:1017600004897638EBA00008040C0109050D020A73
-:10177000060E030B070F004080C02060A0E0105051
-:1017800090D03070B0F0E4D2E6D08AC825030003D0
-:10179000D8D1E32E8BAF4400888EAE00E4D8C0E8E9
-:1017A000048BD82E8A8766178AE08AC88686A900A5
-:1017B00032E0E4988B5E3E84E374548AC18B4E26FB
-:1017C000F6C504740CA808740580E1BFEB0380C95A
-:1017D00040F6C508740CA802740580E17FEB038015
-:1017E000C980884E268BF08A86A500F6C1FD740854
-:1017F000A806741924F9EB0FA8067511F6C5017532
-:10180000040C04EB020C028886A500E60C8BC6844F
-:10181000E775098A86AE00243FE6D2C3C686BA00C1
-:1018200001B00EE81CF8F74638000274E6837E2EFD
-:101830000672E08A86A9008AE08686AA008AC832F3
-:10184000C480C90B22C1C0E4040AE0C45E048B7EDC
-:101850002CB0FFAAB002AB26830703836E2E038948
-:101860007E2CF646382075AB834E3820B000E8D188
-:10187000F7EBA090E41224DFE61281E3FE9F895E7D
-:1018800026836648F7EB7390F6C72075E7E4120CE1
-:1018900020E61232C0E6C6B083E6C680CF20895E5D
-:1018A000268A86A5000C028886A500E60CEB7490BB
-:1018B000F6C74075D3E4120C20E61232C0E6C6B07B
-:1018C00081E6C680E7DF80CB01895E26B006E8713D
-:1018D000F7908A86A50024F9E60C8886A500EB43DC
-:1018E000E4D4E6D08BF825030003D8D1E32E8BAFE8
-:1018F00044008B5E26F6C76075B6F6C3C075D3BAD2
-:10190000C6008B4E1C8B461A3BC8731E014E2A2BF9
-:10191000C189461AC57600F36E8ED98976003D20BE
-:1019200000723D8BC7243FE6D4C385C074398BC891
-:1019300001462AC57600F36E8ED983CB02895E26D6
-:10194000E8D9EDF6C70175398A86A50024F9E60CB9
-:101950008886A500F6C71075CAB002E8E4F6EBC3A6
-:10196000F6C70174EFEBBCF6C70174DC8A86A500EC
-:10197000A802741181E3FFFE81CB0002895E26EB91
-:10198000C78A86A50024FB0C02E60C8886A500EB1E
-:101990009290FDF7DF7FFEFBEFBF0004000405041B
-:1019A00005040104000405040504060406040504F6
-:1019B00005040604060405040504020400040504E5
-:1019C00005040104000405040504060406040504D6
-:1019D00005040604060405040504070407040504B9
-:1019E00005040704070405040504060406040504A9
-:1019F0000504060406040504050407040704050499
-:101A00000504070407040504050406040604050488
-:101A10000504060406040504050403040004050483
-:101A20000504010400040504050406040604050475
-:101A30000504060406040504050402040004050464
-:101A40000504010400040504050406040604050455
-:101A50000504060406040504050407040704050438
-:101A60000504070407040504050406040604050428
-:101A70000504060406040504050407040704050418
-:101A80000504070407040504050406040604050408
-:101A90000504060406040504050433DB8AD88A8796
-:101AA0006C12E6FEC1E302E4CEA8047509A8027434
-:101AB00003E92CFEF9C35053E8CBFC5B58A8027431
-:101AC00003E91CFEF8C333DB8AD88A876C12E6FE72
-:101AD000C1E302E9D0FB9A1AC61A00000200040012
-:101AE00002000600020004000200080002000400D8
-:101AF000020006000200040002000A0002000400C6
-:101B000002000600020004000200080002000400B7
-:101B1000020006000200040002000C0002000400A3
-:101B20000200060002000400020008000200040097
-:101B3000020006000200040002000A000200040085
-:101B40000200060002000400020008000200040077
-:101B5000020006000200040002000E000200040061
-:101B60000200060002000400020008000200040057
-:101B7000020006000200040002000A000200040045
-:101B80000200060002000400020008000200040037
-:101B9000020006000200040002000C000200040023
-:101BA0000200060002000400020008000200040017
-:101BB000020006000200040002000A000200040005
-:101BC00002000600020004000200080002000400F7
-:101BD00002000600020004000200C390DA1494150B
-:101BE0005C13E613DA1BDA1BE613DA1B8B94641220
-:101BF000C1E604A80174355033C08AC2E6FEE4A0F1
-:101C000085C074278BD82E8A9FDA1A52562E8BA83D
-:101C100044008B5628ECA801750D8886AD00240E73
-:101C20008AD82EFF97DC1B5E5AEBCD58A80274367B
-:101C300083C61033C08AC6E6FEE4A085C074278B35
-:101C4000D82E8A9FDA1A52562E8BA844008B56281B
-:101C5000ECA801750D8886AD00240E8AD82EFF975A
-:101C6000DC1B5E5AEBCDC39032E48BD88BD02E8A2E
-:101C70009F9A192E2297921956528AC3240303C69B
-:101C800080E304D0EB2EFF97D61A585EA955007555
-:101C9000D9C3601E062BC08ED8A15C12E6FEE400FC
-:101CA00022C4740833F6E8BFFFEBEE90E40407E4C7
-:101CB000041FB80080BA22FFEF61CF90601E062B90
-:101CC000C08ED8A15E12E6FEE40022C47408BE04F1
-:101CD00000E894FFEBEDE40407E4041FB80080BAC9
-:101CE00022FFEF61CF90601E062BC08ED8A15C1240
-:101CF000E6FEE40022C4741833F6E86BFFA160121C
-:101D0000E6FEE40022C474E5BE0800E85AFFEBDDFD
-:101D1000A16012E6FEE40022C475EDE40407E404C9
-:101D2000A15C12E6FEE4041FE404B80080BA22FFBE
-:101D3000EF61CF90601E062BC08ED8A15E12E6FE2A
-:101D4000E40022C47419BE0400E81CFFA16212E67C
-:101D5000FEE40022C474E4BE0C00E80BFFEBDCA13F
-:101D60006212E6FEE40022C475EDE40407E404A177
-:101D70005E12E6FEE4041FE404B80080BA22FFEF1E
-:101D800061CF601E062BC08ED8A15C12E6FEE480F7
-:101D900084C4740833F6E853FEEBEE90B80080BAC2
-:101DA00022FFEF071F61CF90601E062BC08ED8A1C7
-:101DB0005E12E6FEE48084C47408BE0200E82CFED5
-:101DC000EBEDB80080BA22FFEF071F61CF90601ED5
-:101DD000062BC08ED8A16012E6FEE48084C474088D
-:101DE000BE0400E806FEEBEDB80080BA22FFEF0764
-:101DF0001F61CF90601E062BC08ED8A16212E6FE36
-:101E0000E48084C47408BE0600E8E0FDEBEDB80091
-:101E100080BA22FFEF071F61CF90601E062BC08E95
-:101E2000D8A15C12E6FEE40022C4741833F6E83749
-:101E3000FEA16012E6FEE48084C474E5BE0400E8FE
-:101E4000AAFDEBDDA16012E6FEE48084C475EDA17D
-:101E50005C12E6FEE40407E4041FB80080BA22FF27
-:101E6000EF61CF90601E062BC08ED8A15E12E6FEF9
-:101E7000E40022C47419BE0400E8ECFDA16212E67D
-:101E8000FEE48084C474E4BE0600E85FFDEBDCA1E0
-:101E90006212E6FEE48084C475EDA15E12E6FEE403
-:101EA0000407E4041FB80080BA22FFEF61CF601E70
-:101EB000062BC08ED8A15C12E6FEE48084C47418A0
-:101EC00033F6E827FDA16012E6FEE40022C474E5C3
-:101ED000BE0800E892FDEBDDA16012E6FEE4002200
-:101EE000C475EDE40407E4041FB80080BA22FFEFD4
-:101EF00061CF601E062BC08ED8A15E12E6FEE48084
-:101F000084C47419BE0200E8E2FCA16212E6FEE499
-:101F10000022C474E4BE0C00E84DFDEBDCA16212AB
-:101F2000E6FEE40022C475EDE40407E4041FB800F3
-:101F300080BA22FFEF61CF90601E062BC08ED8A121
-:101F40005C12E6FEE48084C4741833F6E89DFCA1BC
-:101F50006012E6FEE48084C474E5BE0400E88CFCF4
-:101F6000EBDDA16012E6FEE48084C475ED071FB8C6
-:101F70000080BA22FFEF61CF601E062BC08ED8A171
-:101F80005E12E6FEE48084C47419BE0200E85CFCC4
-:101F9000A16212E6FEE48084C474E4BE0600E84B4D
-:101FA000FCEBDCA16212E6FEE48084C475ED071F41
-:101FB000B80080BA22FFEF61CF90601E062BC08E62
-:101FC000D8902AC0E6FEE4CEA801741433DBE8D52D
-:101FD000F6EBEF90B80080BA22FFEF071F61CF90B9
-:101FE000F60605010175EDB001E6FEE4CEA8017428
-:101FF000E3BB0400E8AFF6EBC990601E062BC08E71
-:10200000D890FB90FA2AC0E6FEE4CEA802741333FF
-:10201000DBE8CCF8EBECB80080BA22FFEF071F61D9
-:10202000CF90A80474F033DBE85BF7EBD590601E2B
-:10203000062BC08ED890FB90FAB001E6FEE4CEA845
-:10204000027415BB0400E897F8EBEB90B80080BA77
-:1020500022FFEF071F61CF90A80474F0BB0400E8D3
-:1020600024F7EBD26A001FC6069312099C0EE86B98
-:10207000F2906A001FC6069312299C0EE85DF2904A
-:10208000722072207220CE1D921CE61C1A1E722035
-:10209000821DAE1E381F7220821D72207220381FD2
-:1020A000722072207220F41DBC1C341D641E72202C
-:1020B000A81DF21E781F7220A81D72207220781FA2
-:1020C000FCB940008CCBB864202BFFAB93AB93E200
-:1020D000FAC7064C00A811833E4412007520C706BB
-:1020E0003C00084BC7063000BA1FC7063400FA1F71
-:1020F000F6060501017506C70638002E20C3C7067F
-:102100003C00564B33DB8A1E5412C1E302021E56BA
-:10211000122E8B878020A330008A1E5512C1E30245
-:10212000021E57122E8B87A020A33400C38B869EDD
-:1021300000E6FE86C4E6D0C38B869E00E6FE33D260
-:102140008AD4C351B91027E40A909084C07405E280
-:10215000F659F9C359F8C384C0781E518AE88AC871
-:10216000B80100D3E0098698003AAEA00059751076
-:10217000E8A9E5834E2602F9C39889869800EBF01A
-:10218000F8C384C07812518AE08AC8B80100D3E04D
-:1021900059F7D021869800C3C78698000000C383F2
-:1021A000C2048A86A6000C04EE83EA04C3E893FF07
-:1021B0007204B082E60AC38B4626A8FD74118A8693
-:1021C000A500A806740824F98886A500E60CC3F6C5
-:1021D000C401740A8A86A50024FB0C02EB0CA80239
-:1021E000750F8A86A50024FD0C043A86A50075D8D3
-:1021F000C38A86A500EBCFE4D833DB8AD8C0EB04D2
-:102200002E8A9F6617889EA9008B5E2680E33FF684
-:10221000C7047407A810750380CB40F6C70874077D
-:10222000A880750380CB40885E268A86A500F6C309
-:10223000FD740DA806740824F98886A500E60CC371
-:10224000F6C70174040C02EBF0F6C30275E90C0446
-:10225000EBE7C404C4048504590448044104C303DF
-:10226000820341038202570241028201410182003E
-:1022700041004E02AD0157012D002B002700210027
-:102280001600F404F404A3046F045B045104F40383
-:10229000A3035103A3026D025102A3015101A30044
-:1022A00051006202D9016D01380036003100290069
-:1022B0001B005157BF0200EB0F905156BF0100EBBE
-:1022C00007905156BF0300903C197602B017988BC7
-:1022D000F08A82C4002AE48BF083FE187346D1E6AC
-:1022E0002E8B8C5222F74638800074052E8B8C8200
-:1022F00022F7C7020074123B8E9400740C898E94EE
-:10230000008AC5E6EC8AC1E6E4F7C7010074123B17
-:102310008E9600740C898E96008AC5E6F88AC1E60E
-:10232000F05E59C377068B8E8E00EBC58B8E9000C6
-:10233000EBBFD503F6003E0010000400CA043301D1
-:102340004D00140005000103050709000102030404
-:1023500080841E00A02526000000608BF033FF2E35
-:10236000A150232E8B165223BB3223F74638800010
-:10237000740C2EA154232E8B165623BB3C23B90577
-:10238000002E3B31730A4747E2F7B8FFFFEB1D9081
-:10239000D1EF2E8A8D46232AEDD1EAD1D8E2FAF781
-:1023A000F6050200C1E8022E8AA54B232EA358236E
-:1023B000612EA15823C3080020008000000260099C
-:1023C0000800200080000002000800000100020058
-:1023D0000300040052565785C074053D0109760379
-:1023E000B80109BF5B01F7463880007403BFB20132
-:1023F00033F62E3B84B62376044646EBF5F7E72EFC
-:102400008BBCC02303C783D200D1E7F7F72E8AA481
-:10241000CA235F5E5AC3E43E80BEC30003750CF757
-:10242000467A200074050C80E63EC3247FE63EC356
-:1024300024038886C3008AE0E41024FC0AC4E61062
-:10244000808EA10042E8CEFFC390568BF083E60752
-:10245000D1E62EFFA458249068246C2470247424A0
-:102460007824872487248724B400EB0EB4C0EB0AB9
-:10247000B440EB06B420EB02B4A0E410241F0AC45D
-:10248000E610808EA100425EC3903C0277128AE083
-:10249000E41024F3C0E4020AC4E610808EA10042D6
-:1024A000C3908B5E3884C0741F3C02742083CB08B9
-:1024B0008B462E3B463C770CE888FC7207B024E63E
-:1024C0000A83CB10895E38C383E3F7EBF7F7C310B9
-:1024D0000074F5E86DFC72EC8A86C000E638B02323
-:1024E000E60AEBE08B5E388B462E3B463CE4D87721
-:1024F0000B24FE80CB12E6D8895E38C30C0180CB5A
-:1025000002EBF35033DBC1E804250F0F8AD82E8A83
-:102510008766178ADC2E8AA7661709463E58C3507D
-:1025200033DBC1E804250F0F8AD82E8A8766178A05
-:10253000DC2E8AA76617F7D021463E58C38B463E4D
-:1025400033DB8AD80ADC2E8A877617E62C8AE0E409
-:102550002A240F0AC4E62A8A86A50084E4750DA8F9
-:10256000807411247F8886A500E60CC3A8807504BA
-:102570000C80EBF1C31E6033C933D233F68ED98D94
-:10258000BEFD00578B0584C074168BD1428BFE4F65
-:10259000780938A3E40074084F79F788A2E400466C
-:1025A0005F83C7094183F91072D989B6860089967D
-:1025B0008400611FC353C7466600008B4664A94070
-:1025C00000740DB300A980007402B37F889EC1001F
-:1025D00032DBA90200740380CB40A9004074038061
-:1025E000CB02A90080740380CB01A9301E74038044
-:1025F000CBBCA90020740380CB08A904017403801C
-:10260000CB10A90800740380CB20889EC2005BC356
-:102610000651575016078DBEC400B91F0033C0AA1B
-:1026200040E2FC8B86920089868E00898690005855
-:102630005F5907C3E4D8C0E80453250F008BD82E98
-:102640008A8766178886A9005AC30886AC00C686A2
-:10265000BA0001B00EE8EAE9C3AD36A3B413AD3653
-:10266000A3B613AD36A3B81383E90636F706B6133F
-:102670000F00C38A4626F74648800074020C108873
-:1026800086BD0032C0837E1A00750E8B5E4043808B
-:10269000E3FE3B5E0875020C01837E3A00750D1E59
-:1026A000C55E148B1F1F85DB75020C02F7463810C0
-:1026B0000074020C048B5E7AF7C3020074020C08EB
-:1026C000F7C3040074020C10F7C3080074020C2056
-:1026D000F7C3400074020C408886BF00C3906A00B4
-:1026E0001FC60693120D9C0EE8F1EB90B002E6DADD
-:1026F000F8C333C0E6DAF8C3B001E6D8F8C333C094
-:10270000E6D8F8C3B0FFE84EFAE8A1FAF8C3AC493E
-:10271000E8AFFBF8C390AC49E815FDF8C390AC49AD
-:10272000E867FDF8C390AC49E81FFDF8C390AC49D9
-:10273000E634F8C3AC49E636F8C3AC493C02771F2F
-:1027400084C0751DE41424EFE614E412243FE6125D
-:10275000E416A8047409E8EAF97204B018E60AF865
-:10276000C38AE0E4140C10E614E4120CC0F6C401B1
-:102770007402247FE612F8C3AC49E825FDF8C39043
-:10278000B80040E87DFDE8B4FDE8A8FEB001E8B976
-:10279000FEF8C390B80040E885FDE8A0FDF8C390BE
-:1027A000B80010E85DFDE894FDE888FEB008E899FF
-:1027B000FEF8C390B80010E865FDE880FDF8C3900E
-:1027C000B80080E83DFDE874FDE868FEB002E879F5
-:1027D000FEF8C390B80080E845FDE860FDF8C390BE
-:1027E000B80020E81DFDE854FDE848FEB004E859B3
-:1027F000FEF8C390B80020E825FDE840FDF8C3903E
-:10280000AC49E84814E43C24E70AC4E63CF8C39029
-:10281000B8FC3B89467CE43C0C18E63CF8C3E41267
-:102820000C02E612F8C3E41224FDEBF6E8B5FCF85E
-:10283000C390836638FDF8C3AC49A8017406834E83
-:102840007A20EB0483667ADFE8CBFBF8C3908A86B4
-:10285000A5000C0224FB8886A500E60C814E26010B
-:1028600020AC4932E489466E834E48084946F9C394
-:102870008A86A5000C0224FB8886A500E60C814E02
-:10288000260120ACB40AF6E4EBD8E8FA13E43C24C1
-:10289000F80AC4E63CF8C390AD4949894664A901E9
-:1028A00000741B8BD883E3FA751AA90400740FE433
-:1028B0003E0C02E63EB83844894662F8C390E43ED6
-:1028C00024FCEBEFE43E24FCE63EE8E8FCB8AA403A
-:1028D000EBE6E86EF87205B018E60AF8C390AC496A
-:1028E000E8CFF9F8C390AC49E8CFF9F8C390E868AD
-:1028F000FD750632C0E6DAF8C3B002E6DA36A0B4F7
-:102900001324103410E8160136A1B413A901007481
-:1029100005E8FCFEEB0EA90200740432C0EB02B025
-:1029200001E8DEFE36A1B413E8B513E43C24F80A4E
-:10293000C4E63C36A1B413C1E805250100E8FAFE5F
-:1029400036A0B5132410E859FB32C0368A26B513D9
-:10295000F6C4047409FEC0F6C4087402FEC0E8DBC5
-:10296000FD36A1B613250F00E857F936A1B613C1FD
-:10297000E804250300E8B8FA36A1B613C1E8052536
-:102980000200E805FB36A1B613F6C401750432C097
-:10299000EB0980E402D0ECB0022AC4E8ACFA36F6C7
-:1029A00006B713407405E883FEEB03E884FE36F6B1
-:1029B00006B713207405E865FEEB03E868FEF8C36C
-:1029C000E4120C01E612F8C3E41224FEEBF6E41460
-:1029D00024F00C05E614E42A24F00C06E62AF8C3D9
-:1029E000E42A24F0E62AE41424F00C07E614F8C3E1
-:1029F000AD4949E864F989868E00F8C3AD4949E8D4
-:102A000058F989869000F8C3834E2604E8A8F7F8A1
-:102A1000C390836626FBE89EF7F8C390AC4984C058
-:102A2000750DE41024EFE610808EA10042F8C3E497
-:102A3000100C10EBF190AC493C02760232C0C0E0C1
-:102A400004A82074020C0824188AE0E41224E70A7F
-:102A5000C4E612808EA10044F8C3AC498886C00049
-:102A6000F8C3AC49E63AF8C3AC4984C07408E41230
-:102A70000C04E612F8C3E41224FBEBF6AC49E8D6EA
-:102A8000F67303E827F7F8C3E412A802740424FDE0
-:102A9000E612B8F000E887FA816626FFF3E857F7F8
-:102AA000E89AFAF8C390B88000E857FA804E2708F1
-:102AB000E844F7E887FAF8C3B88000E861FA81666D
-:102AC00026FFF7E831F7E874FAF8C390B81000E889
-:102AD00031FA804E2704E81EF7E861FAF8C3B8100F
-:102AE00000E83BFA816626FFFBE80BF7E84EFAF8B0
-:102AF000C39033C0AC493C017304B001EB063C0CFD
-:102B00007602B00C89461CF8C390814E2600208ABC
-:102B100086A5000C0224FB8886A500E60C834E26C1
-:102B200001F8C390814E2600408A86A5000C0288D9
-:102B300086A500E60CF8C390AC4950E805F658723B
-:102B400008E638B023E60AF8C3F9C390AC50ADE804
-:102B500082F85AF6C201741239869600740C89867E
-:102B60009600E6F086E0E6F886E0F6C202741039D8
-:102B7000869400740A89869400E6E486E0E6EC8395
-:102B8000E903C390E4168886BC00E8E6FA33DBE488
-:102B90000CA806740380CB01A810740380CB02A894
-:102BA00080740380CB04E4128AE024180AD8E4DAA3
-:102BB000F6C4027407A840750380CB20A8027509EB
-:102BC000E42AA80F740380CB40F74638020074094A
-:102BD000E4D8A801750380CB80889EBE00FE86B431
-:102BE00000B00AE85CE4F8C3AC493C027441771FCA
-:102BF00050E84FF558720C84C0740AB012E60A808F
-:102C00004E3801F8C3B011E60A806638FEF8C38B6F
-:102C1000463825FFF7894638A9000475E68A86A557
-:102C200000A81075DE0C108886A500E60CF8C3819C
-:102C30004E3800088A86A500A81074C724EFEBE779
-:102C4000AD49493C0172113C0C770D508AE0E41407
-:102C500025F00F0AC4E614588AC484C07402E64200
-:102C6000F8C3E8CFF9FE86B900B00EE8D4E3F8C3A4
-:102C70003A86AF00741F8886AF008AE080C206B033
-:102C8000BFEE80EA028AC4EE8A86A80080C202EE05
-:102C900080EA068AC4C38B463E85C08A86A5007436
-:102CA00012A808750D0C088886A50080C202EE8067
-:102CB000EA02C3A80874FB24F7EBEC8B462684C019
-:102CC00074168A86A500A802740D24FD8886A500C6
-:102CD00083C202EE83EA02C38A86A500A80275F7C2
-:102CE0000C02EBE85283C20CECC0E8048886A90011
-:102CF0008B5E2680E33FF6C7047407A8087503803F
-:102D0000CB40F6C7087407A802750380CB80885EA5
-:102D1000268A86A50084DB7410A802740A24FD8824
-:102D200086A50083EA0AEE5AC3A80275FA0C02EBE4
-:102D3000EE90FFFF00480030BA20C41A00180012BD
-:102D4000000C0006000300028001C000600030009B
-:102D50001800CD0100018000100010000E000C00D2
-:102D6000080000000000060004000300020001004B
-:102D70005251563C1E7747988BF08A82C40032E449
-:102D800083FE18743D83FE19743E83FE1E772FD197
-:102D9000E62E8B8C322D3B8E94007422898E94000B
-:102DA00083C2068A86A8008AE00C80EE83EA068A3F
-:102DB000C1EE83C2028AC5EE83C2048AC4EE5E59A4
-:102DC0005AC38B8E8E00EBCE8B8E9000EBC8525187
-:102DD0003D05007703B805008BC8BA0200B800D0E3
-:102DE000F7F1050100D1E8595AC38B467AA820743F
-:102DF0000B80BEC3000375040C01EB0224FE894660
-:102E00007AC324038886C3008AA6A8008ADC80E4EB
-:102E1000FC0AC43AC3740B8886A80083C206EE83FA
-:102E2000EA06E8C5FFC30008183828903C04772359
-:102E300032E48BD82E8A87262E8AA6A8008ADC80C8
-:102E4000E4C70AC43AC3740B8886A80083C206EE9E
-:102E500083EA06C384C07402B0048AA6A8008ADC90
-:102E600080E4FB0AC43AC3740B8886A80083C206B8
-:102E7000EE83EA06C3908B5E3884C074343C0274DF
-:102E80003B8A86AF000C04E8E6FD8B462E3B463CB1
-:102E9000771BF7C30004751581CB000483C2028A37
-:102EA00086A50024FA8886A500EE83EA02895E38AA
-:102EB000C38A86AF0024FBE8B6FDEBF1F7C3100030
-:102EC00074EFEBED83C20CEC83EA0CC0E804888657
-:102ED000A900C3908A86A7000C018886A7008BDA18
-:102EE00080C208EE8BD3F8C38A86A70024FEEBEAE3
-:102EF0008A86A7000C02EBE28A86A70024FDEBDAA3
-:102F0000B0FFE852F2E897F2F8C3AC49E861FEF886
-:102F1000C390AC49E8EBFEF8C390AC49E835FFF844
-:102F2000C390AC49E805FFF8C3905283C206B0BF16
-:102F3000EE5283C202AC49EE5A8A86A800EE5AF8D5
-:102F4000C3905283C206B0BFEE5283C206EBE69036
-:102F5000AC493C02770D84C0750B8A86AF0024FD16
-:102F6000E80DFDF8C3508A86AF000C02E801FD5B56
-:102F700083C2088A86A700F6C301740C24DF888602
-:102F8000A700EE83EA08F8C30C20EBF2AC49E8E5B1
-:102F9000FEF8C390B80040E869F5E8F9FCE824FFC2
-:102FA000B001E8A5F6F8C390B80040E871F5E8E58F
-:102FB000FCF8C390B80010E849F5E8D9FCE804FF34
-:102FC000B008E885F6F8C390B80010E851F5E8C5F8
-:102FD000FCF8C390B80080E829F5E8B9FCE8E4FE05
-:102FE000B002E865F6F8C390B80080E831F5E8A5CE
-:102FF000FCF8C390B80020E809F5E899FCE8C4FEA5
-:10300000B004E845F6F8C390B80020E811F5E8856B
-:10301000FCF8C390AC49E8340CF8C390B8FC3B8989
-:10302000467CF8C38A86AF000C80E843FCF8C39066
-:103030008A86AF00247FEBF28A86AF000C40E82F2F
-:10304000FCF8C3908A86AF0024BFEBF2AC49A8011C
-:103050007407834E7A20EB059083667ADFE88AFD59
-:10306000F8C383C2068A86A8000C408886A800EEB2
-:1030700083EA06AC4932E489466E834E2601834ECC
-:103080004808B006E8BBDF4946F9C39083C2068A08
-:1030900086A8000C408886A800EE83EA06ACB40A35
-:1030A000F6E4EBD0E8E00BF8C390AD4949894664FB
-:1030B000A9010074198BD883E3FA750AA904007476
-:1030C0000DB8E23FEB0BE8ECF4B8AA40EB03B838DC
-:1030D00044894662F8C38A86AF00A802740A24FDB8
-:1030E000E88DFB0C02E888FBF8C3AC49E881FCF8EA
-:1030F000C390AC49E879FCF8C390E85CF57505E845
-:10310000E6FDF8C3E8CDFD36A0B41324103410E872
-:10311000260136A1B413A901007405E8FEFEEB0EEA
-:10312000A90200740432C0EB02B001E8E8FE36A147
-:10313000B413E8AB0B36A1B413C1E805250100E8D0
-:103140000CFF36A0B5132410E82BFD32C0368A26BA
-:10315000B513F6C4047409FEC0F6C4087402FEC0B8
-:10316000E8EFFD36A1B613250F00E803FC36A1B643
-:1031700013C1E804250300E888FC36A1B613C1E8B2
-:1031800005250200E8CDFC36A1B613F6C40175048E
-:1031900032C0EB0980E402D0ECB0022AC4E88CFC17
-:1031A00036F606B713407405E88DFEEB03E894FE8F
-:1031B00036F606B713207405E869FEEB03E870FEE7
-:1031C000F8C3F8C38B4638A9040075230D040089A1
-:1031D000463883C2088B462E3B463C7314834E38D8
-:1031E000108A86A70024FE8886A700EE83EA08F8E6
-:1031F000C38A86A7000C01EBEE908B4638A9040029
-:10320000740625FBFF894638F8C3AD4949E8BEFB83
-:1032100089868E00F8C3AD4949E8B2FB89869000E3
-:10322000F8C3834E2604E892FAF8C390836626FB1F
-:10323000E888FAF8C390AC4984C07507808EA30073
-:1032400004F8C380A6A300FBF8C3AC4983C2083CC2
-:1032500002760232C03C017412770B8A86A70024E2
-:10326000EF8886A700EE83EA08F8C38A86A7000CD9
-:1032700010EBEE905283C206B0BFEE5283C204AC94
-:1032800049EE5A8A86A800EE5AF8C3905283C206C5
-:10329000B0BFEE5283C208EBE690AC49F8C3AC492C
-:1032A000E8B4EE7303E8F7EEF8C38A86AF00247F34
-:1032B000E8BDF9B8F000E866F2816626FFF3E8237E
-:1032C000FAE8D2F9F8C3B88000E837F2804E270850
-:1032D000E811FAE8C0F9F8C3B88000E841F2816665
-:1032E00026FFF7E8FEF9E8ADF9F8C390B81000E85A
-:1032F00011F2804E2704E8EBF9E89AF9F8C3B81008
-:1033000000E8FFF1816626FFFBE8D8F9F8C3AC4975
-:10331000F8C383C2068A86A8000C408886A800EEFF
-:1033200083EA06F8C39083C2068A86A80024BFEB0E
-:10333000EA90AC498AE080C20AEC80EA0AA82074CC
-:10334000058AC4EEF8C30651578B4E24E3344989ED
-:103350004E24FF461A8E46028B7E228AC4AA897E9C
-:10336000228B462624FD89462675298A86A500A833
-:1033700002752180C2020C028886A500EE80EA0256
-:10338000EB12C47E003B7E1E760A4F268825897E7E
-:1033900000FF461A5F5907F8C390ACAD83E9038577
-:1033A000C074053D00207205B8FFFFEB03C1E003C8
-:1033B0003B8694007426898694008BD85283C2067B
-:1033C0008A86A8008AE00C80EE83EA068AC3EE8330
-:1033D000C2028AC7EE83C2048AC4EE5AF8C3B08818
-:1033E0008886BC00E88CF233DB8A86A500A80274CC
-:1033F0000380CB01A805740380CB02A80874038066
-:10340000CB04F686A70010740380CB108A86A9002F
-:10341000F6C304750A83C20CEC83EA0CC0E8048A84
-:10342000E08A86AF00A8807408F6C401750380CBDB
-:1034300020F686A70002750AF74638040074038058
-:10344000CB40889EBE00FE86B400B00AE8F3DBF8ED
-:10345000C3FE86B400B00AE8E8DBF8C3AC493C021E
-:103460007437771084C07406804E3801F8C38066C4
-:1034700038FEF8C38B463825FFF7894638A9000483
-:1034800075EA8A86A500A80175E20C0583C2028848
-:1034900086A500EE83EA02F8C3814E3800088A86CA
-:1034A000A500A80174C624FAEBE2AD4949F8C3901F
-:1034B000E811FAFE86B900B00EE886DBF8C3B0FF6B
-:1034C000E8BFECF8C39083667AFBB000E873DBF8E2
-:1034D000C390AC49E853D9721136881E1A0136A040
-:1034E0008E120AC352BA0001EE5AF8C3AC4932E454
-:1034F00036A38612050600368B1E88122BD8368915
-:103500001E8A12F8C390AD8BD8AD83E90403C32B98
-:103510004676894678F7467A0200740A83667AFD11
-:10352000B80000E81CDBF8C3061607AC49250F00FD
-:103530006BC0098DBEFD0003F8AC49250F00AA85BC
-:10354000C074082BC8518BC8F3A459E827F0E8448D
-:103550000307F8C333C0AC4936A3B21336A3B01384
-:10356000F8C383667AEFE82C03F8C390834E7A1091
-:10357000EBF4E89BF0F8C390AD3C19770E3C19775B
-:103580000A8BF881E7FF0088A6C400F8C390834E39
-:103590002620AC4932E4D1E08BD8C1E30203C389D1
-:1035A000466E834E4804B006E897DA4946F9C39060
-:1035B000FE86B300B00AE889DAF8C39033C0AC499C
-:1035C0006BC00A89868A00F8C390AC4932E43D0A90
-:1035D000007705B80A00EB083D5A007203B85A009C
-:1035E00051F7D80564008BC88B4644F7E1B96400F5
-:1035F000F7F189464659F8C3AC49E885EBF8C39022
-:10360000AC4984C07507816638FFFDF8C3814E3828
-:103610000002F74638400075088A86A9008886AA05
-:1036200000F8C3905156E87F0C5E59F8C390FE86AF
-:10363000B600B00AE80BDAF8C390FE86B700B00A0D
-:10364000E8FFD9F8C390FE86B800B00AE8F3D9F8CD
-:10365000C39000905155AC2EA2523633C9AD8BF9B0
-:10366000C1E705A9010074232E8BAD4400837E08B9
-:103670000074182E803E523601740960B004E8BB15
-:103680000C61EB0760B0FBE8EC0C614747D1E875D3
-:10369000D24183F90472C65D5983E905F746384083
-:1036A000007405E887EAF8C3E88DEAF8C39036C6E7
-:1036B00006C81301F8C333C0AC4936A38012AC4925
-:1036C000362B068812F7D836A38212F8C390DE266E
-:1036D000DE26EC26F226F826FE2604270E271627DD
-:1036E0001E2726272E273427BE34C634D2343A2745
-:1036F000782780279427A027B427C027D427E0273E
-:10370000F42700281028EC34DE261E2826282C2832
-:10371000322838284E288A28063528359828BE2889
-:10372000D228DE28E628543562356C35EE28C029CB
-:10373000C829CE29E02972357835F029FC298E3543
-:10374000082A122A1C2AB035362ABC355A2A622A7F
-:10375000682ACA357C2AF835882AA62AB82ACC2AAB
-:10376000DE2AF22A00360A2B242B2436382B4C2B47
-:10377000842B2E363A3646365436E82BAE36402C5D
-:10378000622CB6367028DE26DE26D42EE82EF02EE9
-:10379000F82E002F0A2F122F1A2F222F2A2F422FF6
-:1037A000BE34C634D234502F8C2F942FA82FB42F70
-:1037B000C82FD42FE82FF42F083014301C30EC34ED
-:1037C000DE2624303030383044304C306230A43083
-:1037D00006352835AA30CE30D630EA30F2305435AE
-:1037E00062356C35FA30C231C231C431FA317235CA
-:1037F00078350A3216328E3522322C323632B035D6
-:103800004A32BC3574328C329A32CA359E32F8351F
-:10381000AA32C632D832EC32FE320E3300361233C0
-:103820002633243632339A33DE332E363A36463652
-:1038300054365C34AE36AA34B034B6368C30E32815
-:10384000F7463840007532E8E3E833C0AC493D5BE9
-:103850000077198BD8D1E32EFF97CE36720B85C92E
-:1038600075E88B4648E81A0CC34E41C36A001FC670
-:103870000693120C9C0EE863DAE8BCE833C0AC494E
-:103880003D5B0077E78BD8D1E32EFF97863772D95F
-:1038900085C975E8C3F7467A1000750F83BE8400AA
-:1038A000007408B8483A89868000C381BE8000EC65
-:1038B0003C74F783BE8800007505B8EC3CEBE7F775
-:1038C000467A080075401E608B8E88003B4E7477E8
-:1038D000333B4E78772EC47E108BDF26033D47475F
-:1038E00033C08ED88DB6F4008BC1F7467A010075CF
-:1038F0001DF3A4260107294678014676294674B0AF
-:103900000CE83ED7611FC78688000000EBACE3E3FC
-:103910005090AC247FAAE2FA58EBD8908B8E8800A6
-:10392000E3468B9E8A0085DB743EBA50FFED2B8602
-:1039300082003BC372378DB6F400C47E108BDF2645
-:10394000033D47478BC1161FF7467A01007524F3E4
-:10395000A4260107294678014676294674C7868839
-:10396000000000B00CE8DAD683667AF7C3B000E84E
-:10397000D0D6C3E3DC50AC247FAAE2FA58EBD29055
-:103980001E6033C08ED88DB6FD008B8688008B9666
-:1039900084003A0475108BDE468BC88DBEF400F3AC
-:1039A000A674668BF39083C6094A75E68DB6FD0052
-:1039B0008B9684003A0473108BDE468BC88DBEF460
-:1039C00000F3A674768BF39083C6094A75E68DB62C
-:1039D000F400ACF7467A01007402247F1EC55E1025
-:1039E0008B37884002468937FF4E78FF4676FF4E78
-:1039F000741F8B8E880049898E8800E3438DB6F44E
-:103A0000008BFE46F3A4E97DFFC576108B1C85DB99
-:103A1000740803F383C60383E6FE8B8684002BC2FF
-:103A2000B48089044646C7040000897610834E7A24
-:103A300004C78688000000611FF9C333C0611FC33B
-:103A4000B08084C0611FC3908B4E782B8E88007627
-:103A50002789B68C008B5E743BCB72028BCB3BC844
-:103A600072028BC88BC1E34433D28EC28BD183BE2A
-:103A70008800007406E98E0033C0C38B5E10031FFC
-:103A8000434352F7467A0100752AAC8DBEE4008BA1
-:103A90008E8600F2AE74348807434A75ED588B5E0B
-:103AA0001001072946780146762946748BC62B8675
-:103AB0008C00C390AC8DBEE4008B8E8600F2AE7499
-:103AC0000A247F8807434A75EBEBD28886F400C747
-:103AD0008688000100582BC2740E8B5E10010729E6
-:103AE000467801467629467440E894FE72BE4A75CF
-:103AF0001583BE8A000074B4BA50FFED8986820037
-:103B0000834E7A08EBA68DBEF40003BE8800A4FFA6
-:103B1000868800E86AFE729479064A748FE95BFF32
-:103B20004A74CEEBE19050E811CC8B467439467262
-:103B300074271E565133C9C5760CAD74107809032D
-:103B4000C805010024FE03F03B761076ED294E7681
-:103B5000014E78E837CC595E1F58C390C47E1026BA
-:103B60008B1D83C30326891D4B03FBAB91AAB803AE
-:103B700000294678014676294674C390C47E1026F3
-:103B80008B1D4326891D4303FBAAFF4E78FF467613
-:103B9000FF4E74C3E8E5FFC38081848582838687F6
-:103BA00050538ADC83E30ED1EB2E8A87983B08863C
-:103BB000B000FE86B100B00AE887D45B58C3508AD3
-:103BC000C8B8FF00E895FF58C3908A86BB00E8ABF1
-:103BD000FFC3E8CBFFE8F2FFC390E8C3FFE8B4FF00
-:103BE000C39033C0E895FFC3B8FF0033C9E86CFF4A
-:103BF000C390B8FF01B110E862FFC390C3FC3BE281
-:103C00003BF23BF23BFC3BE23BE83BE83BFC3BE26C
-:103C10003BE83BE83BFC3BE23BE23BE23B00100085
-:103C20000000100000001000000010000000100054
-:103C3000000010000000100000001000000008004C
-:103C40000000080000000800000008000051538B2D
-:103C50004E3881E1FFEEA804740481C900018AE0B6
-:103C600080E4032418D0E40AC433DB8AD82E8B877F
-:103C7000FD3B89467C2E0B8F1D3C894E38D1EB2EA7
-:103C80008AA73D3C5B59C3AC493C01721D74203C82
-:103C900003722374283C08722B74303C20723774F2
-:103CA0003ABBDA3B32E4895E7EC3BBA03BEBF5BB9B
-:103CB000943BB401EBF0BBFC3BB402EBE9BBE23B51
-:103CC000B403EBE2BBBE3BB404EBDBBBCA3BAC4989
-:103CD0008886BB00EBCEBBD23BEBF3BBFC3BEBC41B
-:103CE000A9040075D1A9080075DAEBD18B5E748B3D
-:103CF0004E783BCB72028BCB3BC872028BC88BC118
-:103D0000E32CC47E108BDF26033D4747F7467A013C
-:103D100000751CF7C70100740249A4D1E9F3A5732B
-:103D200001A4260107294678014676294674C35026
-:103D300053BB7F7FF7C70100740549AC22C3AAD1EA
-:103D4000E9E31D9CAD23C3AB497414AD23C3AB4958
-:103D5000740DAD23C3AB497406AD23C3ABE2E59D3F
-:103D60007304AC22C3AB5B58EBB8E8CEC98B5E38AA
-:103D7000F7C310047501C3F7C340007405E8B8E346
-:103D8000EB03E8A8E3816638EFFBF6C310743CF65A
-:103D9000C3027406E4D80C01E6D8F6C30474118398
-:103DA000C2088A86A7000C01EE8886A70083EA086D
-:103DB000F6C308740FE88BE3720A8A86C000E638FF
-:103DC000B023E60AF7C300047501C3F7C300087502
-:103DD000F98A86A500F6C340750DA81075EC0C1085
-:103DE0008886A500E60CC3A80175DF83C2020C0516
-:103DF000EE8886A500C3B000E847D2EB0FB002E81A
-:103E0000900EEB08836638DF834E7A0233C08ED87B
-:103E1000FAA0921240A292123C05721EC60692129D
-:103E200000FBB001E86B0EFAA1260123062A01A8C7
-:103E3000017507E8E207E8610990B000E837D2FBB6
-:103E400085ED74B9FAF7467A460075C08B46783D21
-:103E50000A0072B08B4E7483F950729A836638DF11
-:103E6000C576148B463A85C07558AD85C0750FE888
-:103E7000F8FEF7467A08007493E8A0FAEB8E3B76DA
-:103E8000047621B90200394E2E7705C7462E000070
-:103E9000568B762C897604C7040000464689762C1A
-:103EA000294E2E5E85C07917F6C4107405FF567C26
-:103EB000EB03FF567E897614B00CE885D1EB86893A
-:103EC000463AFF96800029463A897614B00CE8718C
-:103ED000D1E971FF0000000000000000080410029A
-:103EE00001200000000000000000000000000000B1
-:103EF00000000000808080808080808080808080C2
-:103F000080808080808080808080808080808080B1
-:103F100080808080808080808080808080808080A1
-:103F20008080808080808080808080808080808091
-:103F30008080808080C0C0C0C0C0C0C0C0C0C0C0C1
-:103F4000C0C0C0C0C0C0C0C0C0C0C0C0C0C0C080B1
-:103F500080808000808080808080808080808080E1
-:103F60008080808080808080808080808080808051
-:103F70008080808080808080808080808080808041
-:103F80008080808080808080808080808080808031
-:103F90008080808080808080808080808080808021
-:103FA0008080808080808080808080808080808011
-:103FB0008080808080808080808080808080808001
-:103FC00080808080808080808080808080808080F1
-:103FD000808080804E417841D041F44106421842B1
-:103FE000C3908E46028B7E22897E6C806627FD8B75
-:103FF000562483FA0472E983EA028BD93BCA76021B
-:104000008BCAB00A57518BFEF2AE8BC1595F751E39
-:1040100050402BC874062BD12BD9F3A4594B4A4AD4
-:10402000B00DAAA43BCA76028BCAE313EBD42BD9FA
-:10403000F7C601007402A449D1E9F3A57301A4896C
-:104040007E222B7E6C297E24017E1A8BCB807E26DD
-:10405000027405806626FDC360B0FDE8180361C3E5
-:10406000C390E87C0272F990834E26208B466A89C1
-:10407000466E8B46480D040025BFFF894648B006B2
-:10408000E8BFCFC3897E222B7E6C017E1A297E2455
-:10409000807E26027405836626FDC360B0FDE8D5E8
-:1040A0000261C3908ABEC200EB24F7464840007507
-:1040B000B18E46028B7E22897E6C8B562483EA0A5F
-:1040C000789E03D7806627FD33C08ABEC200E3B462
-:1040D0003BFA77B0AC49932E8A87D43E9322DF75A2
-:1040E00017AAE3A03BFA779CAC49932E8A87D43E6B
-:1040F0009322DF7503AAEBD6F6C37F7505FF4666EC
-:10410000EBDFF6C340750C8BD883EB08D1E32EFFB1
-:10411000A7D43FFF46662C20EBC785C0742C894688
-:104120006A834E4840897E222B7E6C017E1A297E4E
-:1041300024807E26027408836626FDE8A301C360FE
-:10414000B0FDE8310261E89801C3E957FF908B5E4A
-:10415000664B7803895E66AA8B5E64F7C3002075A0
-:1041600003E940FFF7C3400074088A86C100AAE94A
-:1041700032FFB83200EBA3908B5E66895E6883C322
-:104180000880E3F8895E668B5E6481E3001881FB3A
-:104190000018742DAA85DB7425F746644000751855
-:1041A00081FB0010740C8B46662B4668C1E004E965
-:1041B00068FFB86400E962FF8A86C100AAAAE9E341
-:1041C000FE518B4E662B4E68B020F3AA59E9D4FEFF
-:1041D0008B5E66895E688B5E64F7C324007410C7CB
-:1041E00046660000F7C304007405B00DAAB00AAA21
-:1041F000EB489090AAF7466400407406B8D007E9EF
-:1042000018FFE99FFE90AAF7466400807406B8D0B4
-:1042100007E906FFE98DFE908B5E66895E6885DBA7
-:10422000750C8B5E64F7C310007406E976FE8B5E36
-:1042300064F7C308007427B00AAAF7C32000751FEB
-:10424000F7C300017503E95BFEF7C340007506B8CC
-:104250006400E9C5FE8A86C100AAAAE946FEAAC78B
-:1042600046660000F7C3000674F1F7C340007419F6
-:104270008A86C10081E3000681FB00047206760293
-:10428000AAAAAAAAAAAAE91BFE81E3000681FB004A
-:1042900004720E7606B89600E97FFEB86400E979EC
-:1042A000FE8B4668E973FE90368B0EDA1283F93284
-:1042B000731D1E0633C08ED88EC08D764CBFDC12A7
-:1042C00003F9A5A5A583C106890EDA12071FC3B09D
-:1042D00008E86ECDC390836648FEE893C4E8C8FF43
-:1042E000C3F6462702750F9CFA837E1A0074098074
-:1042F0004E27019DF9C3F8C35052F7463840007469
-:104300001DE834DE83C20AECA840752783EA088AD8
-:1043100086A5000C028886A500EE5A58EBD1E80C61
-:10432000DE8A86A50024FB0C028886A500E60C5ACE
-:1043300058EBBC804E27025A589DF8C30846269C6D
-:10434000FA8A8EA500F7463840007514F6C1067447
-:1043500023E8D9DD8AC124F98886A500E60C9DC32F
-:10436000F6C102740FE8D0DD83C2028AC124FD8841
-:1043700086A500EE9DC38B5E2622C3884626740167
-:10438000C3806627FD9CFA8A8EA500F74638400058
-:104390007516F6C104750FE893DD8AC124FD0C047F
-:1043A0008886A500E60C9DC3F6C10275F9E888DD94
-:1043B00083C20AECA820750E83EA088AC10C028821
-:1043C00086A500EE9DC383EA0A33C98A4E1C8B463C
-:1043D0001A3BC8731B014E2A2BC189461A1EC5768B
-:1043E00000F36E1F89760083C2028A86A500EBCD9A
-:1043F00085C0741201462A8BC81EC57600F36E1F55
-:10440000897600894E1AF6C701752380CB02895E32
-:1044100026E808C383C2028A86A50024FDEE8886AA
-:10442000A500F6C7107505B002E816CC9DC383C27F
-:10443000028A86A500EB86908BD18B46243BC876FA
-:10444000028BC82BD12BC18BD9E322806627FD8E2E
-:1044500046028B7E22F7C601007402A449D1E9F31B
-:10446000A57301A4897E22894624015E1A8BCA8025
-:104470007E26027405806626FDC360B0FDE8F6FE68
-:1044800061C350E40A84C0750A8686A10084C074A2
-:104490000AE60A580C20894648F9C35824DF8946A1
-:1044A00048F8C390FBB002E8E807FAE82E01FBB039
-:1044B00001E8DE07FAB002E8BCCBFB85ED74E5FA53
-:1044C0008E5E0AFB90FA8B46488B7640A88C75DE90
-:1044D000A820741A50E855DC58E8A6FF7310B00203
-:1044E000E85FCBEBC99025FF008BC8EB3690A801A5
-:1044F00075224683E6FE3B76087479AD8AFCB3F0FC
-:1045000022FB3AFB74E03ABEA000742EE8D2FD73A1
-:1045100077EB9B908AE024FC8846488B4E4AF6C491
-:1045200002741DE8BBFD7286E813F3897640E393BD
-:10453000834E4803894E4AE974FF25FF0F8BC890CC
-:104540008B86980085C0741A518A8EA000C0E90439
-:10455000BA0100D3E25923C2740803F1897640E915
-:1045600061FFFF5662E3F5834E4801894E4A897622
-:1045700040E93AFF814E2600108B46503B46467775
-:1045800003E852FDE927FF9088BEA000EBAC0A06C5
-:1045900090128AE0BA0601B004EEEC84C07512B045
-:1045A00004EE8AC4EE32E4A8807406C706841200C2
-:1045B0000088269012C30A0690128AE0BA0601EC1F
-:1045C000A80175EDBA08018AC4EE32E4A88074E14E
-:1045D000C7068412000088269012C39036F706247E
-:1045E0000101007530368B0EDA1280F936732633EE
-:1045F000C08EC08ED8BFDC1203F9B008E877CA8538
-:10460000ED740E8D764CA5A5A580C10680F9367295
-:10461000E9890EDA12C3C390F7062601010075F688
-:104620008B0E201385C975EE33C08EC08ED8BF2483
-:1046300013B93600B00AE83DCA85ED7506E91201E6
-:10464000E90A0133DB8A464C8AA6B300FECC780E19
-:1046500088A6B3000ADCB40AAB83E90276E28AA634
-:10466000B200FECC780E88A6B2000ADCB408AB8398
-:10467000E90276CC8AA6B100FECC78188ABEB000DA
-:10468000750488A6B00088A6B1000ADC8AE7AB836F
-:10469000E90276AC8AA6B400FECC781F88A6B400E6
-:1046A0000ADCB40BAB8A86BC008AA6BD00AB8B8645
-:1046B000BE00AB83E90676888A464C8AA6B600FE21
-:1046C000CC781988A6B6000ADCB40CABE8DBCBAB1F
-:1046D0008B462AAB83E90676748A464C8AA6B700D5
-:1046E000FECC781988A6B7000ADCB40DABE8BACBCB
-:1046F000AB8B4634AB83E90676538A464C8AA6B820
-:1047000000FECC781988A6B8000ADCB40EABA15024
-:1047100012ABA15212AB83E90676328A464C8AA6C6
-:10472000B500FECC781888A6B5000ADCB40FAB8BB8
-:10473000869A00AB8B869C00AB83E906760F84DB00
-:104740007503E9EFFEB00AE8F8C8E9E7FEB00AE849
-:10475000F0C8F7D983C1368BC10D800086C4A3226F
-:10476000134141890E2013C3A184122BC17211A3DE
-:104770008412BE2213D1E9F36F90890E2013F8C37F
-:10478000F9C3C381EF6A1374F98BC70D800086C427
-:10479000A368134747893E6613C3F7062A01010041
-:1047A00075E08B0E6613E30780F92077D54949330E
-:1047B000C08EC08ED8BF6A138BF703F983C6343B13
-:1047C000FE77C0B00EE8AEC885ED74B78A464C8A55
-:1047D000B6B900FECE781588B6B9008AA6A90080C1
-:1047E000CCC0AB84F67405B00EE856C88AB6BA00E1
-:1047F000FECE78CB8A9EA9008ABEAB008A563F8A3D
-:10480000F332F70AB6AC00C686AC000022F2744B55
-:10481000F6C608740FB402F6C3087502B403AB8081
-:10482000E6F77437F6C601740FB400F6C3017502DB
-:10483000B401AB80E6FE7423F6C602740FB404F62E
-:10484000C3027502B405AB80E6FD740FF6C60474AE
-:104850000AB406F6C3047502B407ABC686BA0000F4
-:10486000889EAB00E958FF90A184122BC17211A35E
-:104870008412BE6813D1E9F36F90890E6613F8C3F2
-:10488000F9C3A1841241412BC17223A384128BC1AD
-:10489000484832E40C8086C4EF9090909090BEDC43
-:1048A000124949D1E9F36F90890EDA12F8C3F9C3BE
-:1048B0008AC88A464CB40183EB06EF9090909090A2
-:1048C000B80100EF90909090908AC1EF90909090F6
-:1048D00090E99700E9AC0033C08ED8891E8412C3DA
-:1048E000368B1E8412FB90FAB00CE889C785ED74F4
-:1048F000E6C5760C83FB1472DBFB90FAAD85C078BD
-:10490000AF74E28BFE03F8368B0E86123BC1770242
-:104910008BC883EB043BD977028BCB33C08A464CE0
-:10492000EF90909090908BC1EF90909090904180FC
-:10493000E1FE2BD951D1E9F36F90598BC74024FE8A
-:104940003BC674272BFE4E4E538B5E103BF3721307
-:10495000031F83C30380E3FEC7070000836E740256
-:10496000895E105B893C89760CEB8989760C3976F7
-:104970001077817208833C007403E977FFE80DBE6D
-:10498000E962FF36891E8412B00CE8B5C633C08ECA
-:10499000D8C3A184123D10007277BA04013B068887
-:1049A000127506C7067E1200008B0EDA12E30BE8C2
-:1049B000D0FE7257C7067E12FF7F8B0E2013E30BCB
-:1049C000E8A5FD7246C7067E12FF7F8B0E6613E3D5
-:1049D0000BE894FE7235C7067E12FF7FA12801A95D
-:1049E00001007503E8F9FE803E8D1200751DA1845B
-:1049F000123D200076153B0682127609A17E123BFD
-:104A0000068012720C800E901280C3B080FF167C5C
-:104A100012C3800E901240C36A001FC6069312177D
-:104A20009C0EE8B7C86A001FC6069312209C0EE8C9
-:104A3000AAC86A001FC6069312169C0EE89DC8906D
-:104A4000BA0601ECA82075CAFB90FABA0401ED90F1
-:104A5000909090903A06941277BE33DB8AD8D1E3D7
-:104A60002E8BAF4400C47E0885FF74B9F6C4C075B0
-:104A70005532C0C1E00280E4F08BF0ED9090909050
-:104A80009085C074BB8BC84180E1FE0BC68B5E5025
-:104A90004B4B2BD9789CAB8BC1404001464ED1E9A2
-:104AA000F36D90895E50897E088B462680E4EF89FD
-:104AB0004626F6C401750CF746480C007505B00291
-:104AC000E87FC5E97AFF86C48BC883E13F4180E176
-:104AD000FEE30A3C807209243FB4F0EBB0E960FFCA
-:104AE000253F0033FF8EC7BF96128BF7D1E9F36DD8
-:104AF000908BC8E848EDE947FF906A001FC606930F
-:104B0000121B9C0EE8D5C790601E0633C08ED88E4F
-:104B1000C0BA0601ECA80474E1B006EEECA28C1257
-:104B2000A8407411A18812A38412C6068D1200E851
-:104B300060FEA08C12A8807403E804FFB80080BA5D
-:104B400022FFEF071F61CF906A001FC60693121B5A
-:104B50009C0EE887C790601E0633C08ED88EC0BA00
-:104B60000601ECA80474E1BA0801ECA28C12A8407A
-:104B70007411A18812A38412C6068D1200E812FED9
-:104B8000A08C12A8807403E8B6FEB80080BA22FF99
-:104B9000EF071F61CF90EE86E0EE86E0EC86E0EC5A
-:104BA00086E080E1FEF36C9080E1FEF36E900500FC
-:104BB0007547A84B05007548A84B0500A348A84BAE
-:104BC00005003549A84B06009848964B0600BA48A0
-:104BD000964B0600C348964B0600CB48964B060002
-:104BE0002049964B06002849964B06004E4A9C4B9E
-:104BF00006007B4A9C4B05009E4AA24B0500EC4AEE
-:104C0000A24B00001E06833E4412007409A0060158
-:104C100024303C30741A8CC88ED88EC0BBAE4B8BFF
-:104C20000FE30D8B7F028B7704F3A483C306EBEFB6
-:104C3000071FC39033C0A33E01B90C01BE40018BD6
-:104C4000FE81C6B40F89048BC62BF13BC777F6A350
-:104C50003C01C3901E0660368B2E3E018B5E003BEE
-:104C6000EB742B8B7602891C89770236A13C018973
-:104C7000460036892E3C018BEBFF4E0674088B6E86
-:104C800000FF4E0675F836892E3E018B66046107DB
-:104C90001FC31E0660368B2E3E0198894606896624
-:104CA000043B6E0074108B6E00FF4E0675F836895B
-:104CB0002E3E018B660461071FC3C3901E06609CD5
-:104CC000FA33ED8EDD8B2E3C0185ED743D8B4E006D
-:104CD000890E3C018BCC8DA60A01561E06608966A2
-:104CE00004C746080F1AC7460601008B1E3E018501
-:104CF000DB741D8BC58707894600895E028BD889C6
-:104D00006F028BE19D61071FF8C39D61071FF9C307
-:104D1000892E3E01896E00896E0287E19D8BE1EB51
-:104D2000E4000D0A5465726D696E616C73207375D1
-:104D300070706F727465643A0D0A312920414E53C8
-:104D40004920636F6D70617469626C650D0A322968
-:104D500020577973652033300D0A506C6561736597
-:104D60002073656C6563743A20000D0A636F646597
-:104D7000207365676D656E743D000D0A4D6F6E6939
-:104D8000746F722076322E350A0D0A3E000D0A50DD
-:104D90006172646F6E3F000D0A4E6F206164647231
-:104DA00065737320737065636966696564000D0AD5
-:104DB0003A000D0A004C6F633D000D0A4641544114
-:104DC0004C204552524F523D000D0A4D6F6E697492
-:104DD0006F7220636F6D6D616E64733A2D0D0A20E2
-:104DE0002020442C645B5B787878783A5D7878781A
-:104DF000785D202D2064756D70206D656D6F727902
-:104E00000D0A2020204C2C6C5B5B787878783A5D1A
-:104E1000787878785D202D2064756D702073696EC8
-:104E2000676C65206C696E650D0A202020452C6535
-:104E30005B5B787878783A5D787878785D202D209B
-:104E400065646974206D656D6F72790D0A2020208C
-:104E5000462C665B5B78787878205D787878785D2A
-:104E6000202D2066696C6C206D656D6F72792070E5
-:104E70006172616772617068730D0A202020495B5E
-:104E8000787878785D202020202020202020202D78
-:104E900020776F726420696E7075742066726F6D12
-:104EA00020706F72740D0A202020695B7878787802
-:104EB0005D202020202020202020202D20627974B9
-:104EC0006520696E7075742066726F6D20706F72E8
-:104ED000740D0A2020204F78787878207878202068
-:104EE000202020202020202D206F757470757420C4
-:104EF000776F726420746F20706F72740D0A2020B7
-:104F0000206F787878782078782020202020202042
-:104F100020202D206F75747075742062797465205F
-:104F2000746F20706F72740D0A202020475B5B78CD
-:104F30007878783A5D787878785D2020202D206721
-:104F40006F746F20616464726573730D0A20202092
-:104F5000575B5B787878783A5D787878785D202050
-:104F6000202D207761746368206120776F72640D53
-:104F70000A20202043202020202020202020202024
-:104F800020202020202D20696E7465727275707447
-:104F900073206F66660D0A202020532020202020D9
-:104FA00020202020202020202020202D20696E7409
-:104FB00065727275707473206F6E0D0A20202073F5
-:104FC00020202020202020202020202020202020E1
-:104FD0002D2073696E676C6520737465700D0A20EF
-:104FE000202042787878782020202020202020203F
-:104FF0002020202D20627265616B706F696E7420B5
-:105000007365740D0A20202062202020202020209B
-:105010002020202020202020202D20627265616B1E
-:10502000706F696E7420636C6561720D0A202020B8
-:10503000522020202020202020202020202020203E
-:10504000202D207265737461727420627265616BC9
-:10505000706F696E740D0A2020207220202020209D
-:1050600020202020202020202020202D2072656755
-:105070006973746572732061742062726B70740D51
-:105080000A202020582C78206E202020202020204C
-:1050900020202020202D206578616D696E652063B9
-:1050A00068616E6E656C206E0D0A202020482C3FD2
-:1050B00020202020202020202020202020202D20E3
-:1050C00074686973206D657373616765001B5B327B
-:1050D0004A1B5B313B3148414E5349205465726D48
-:1050E000696E616C0D0A0A001B5B4B001B5B4A007A
-:1050F0001B5B324A1B5B313B3148001B5B44201B6E
-:105100005B44001B5B313B373248001B5B003B00BC
-:1051100048001B5B73001B5B75001B7A2B0B7F1B0E
-:105120007A2E0C7F1B7A2D087F1B7A2C0A7F1B7A24
-:1051300022087F1A57797365203330205465726DC9
-:10514000696E616C0D0A001B54001B59001A001E89
-:105150000008200800001B3D0000001B46000D0059
-:105160003F4464456546664767486849694F6F43F1
-:1051700063537342625272577758784C6C3C60D4D8
-:1051800057D45750585058D659D659B459B4593C99
-:10519000603C606C57485726570657905790579871
-:1051A00057485F0C5F585F335F405FA057A057FEC2
-:1051B00059FE59DC57DC5788619861C061CC61D8D1
-:1051C00061F66102622262F8564A625862605920B2
-:1051D00020666C6167733D00202061783D002020CF
-:1051E00062783D00202063783D00202064783D00F7
-:1051F000202063733D00202064733D0020206573F0
-:105200003D00202073733D00202064693D00202074
-:1052100073693D00202062703D00202073703D00C6
-:10522000202069703D00206368616E656C3D002040
-:105230002020207365673D002074695F7374723DA0
-:10524000002074695F746F733D002074695F6D6145
-:10525000783D002074695F6261733D002074695F6E
-:1052600073697A3D002074695F7374663D00207431
-:10527000695F726F6F3D002074695F666C673D0007
-:105280002074695F746F743D002072695F70636E93
-:105290003D002072695F7374723D002072695F7314
-:1052A00074663D002072695F726F6F3D0020726905
-:1052B0005F6261733D002072695F73697A3D00200F
-:1052C00072695F746F743D002072695F6D696E3D35
-:1052D000002072695F666C673D002072695F746FC1
-:1052E000733D002072695F7468723D002074685FCE
-:1052F0007374663D002074685F7374723D0020749F
-:10530000685F6261733D002074685F73697A3D0075
-:105310002074685F7472673D002074685F666C6714
-:105320003D002074685F636E743D002072685F7397
-:1053300074723D002072685F7374663D002072686D
-:105340005F6261733D002072685F73697A3D00207F
-:1053500072685F7370613D002072685F61736F3DBA
-:10536000002072685F726F6F3D002072685F666C2C
-:10537000673D00206D5F636172653D002070745F62
-:10538000666C6F3D002061735F666C6F3D0020723C
-:105390006D5F666C6F3D00202020715F696E3D007F
-:1053A0002020715F6F75743D0020715F6472616EC3
-:1053B0003D002020715F74696D3D00202020715FE9
-:1053C00066633D0020715F737461743D0020715FFE
-:1053D000646174613D0020715F6D6F646D3D0020FC
-:1053E00068616E645F6F3D002068616E645F623D5E
-:1053F000002068616E645F653D002068616E645FD7
-:10540000693D0020206F706F73743D002020746927
-:105410006D656F3D0020637573746D313D002063D1
-:105420007573746D323D0020637573746D643D0057
-:10543000207478726174653D0020727872617465C1
-:105440003D002020635F6D61703D0020635F6164FB
-:1054500064723D0020635F616973723D0020635F89
-:10546000787461673D0020635F646566723D00206B
-:10547000635F666C73683D002074786D6178733D7E
-:10548000002072695F656D733D002020635F6C735F
-:10549000723D002020635F6965723D002020635FDC
-:1054A0006663723D002020635F6D63723D002020C3
-:1054B000635F6C63723D002020635F6473733D0023
-:1054C00020635F647373693D0020635F647373726C
-:1054D0003D002020635F6973723D002020635F639D
-:1054E00061723D002020635F6566723D0020635F4E
-:1054F000657273743D0020635F65636E743D0020C8
-:10550000635F62726B633D0020635F626F6B633D3C
-:105510000020635F7265706C3D0020635F6363739E
-:10552000723D0020635F737474313D0020635F73CC
-:105530007474323D002BC08ED88EC0E8C200E8E5FE
-:1055400000FABF8400C705DC568C4D02BF0C00C7B3
-:10555000056E5E8C4D02BF0400C705BA5E8C4D021D
-:10556000E8F10090E84901E81600F490E8E500BE93
-:10557000BA4DE8090CA09312E85D0CE8C209EBE40F
-:10558000E8D50CE8C40C0AC074F68B1EF8793C0D03
-:10559000742E3C0874173C7F741383FB207FE188D2
-:1055A00087D67943891EF879E8770CEBD30BDB7447
-:1055B000CF4B891EF8798B36167AE8C10BEBC19078
-:1055C000E80200EBBBC687D679000BDB741EA0D6C1
-:1055D00079BF6051B91D008BD9060E07F2AE077571
-:1055E00017412BD9D1E32EFF977D519033C0A3F8FB
-:1055F00079BE894DE8870BC3BE8D4DE8800BEBEC7F
-:10560000BA0002B093EEB055EEBA1002B093EEB00D
-:10561000AAEEBA0002EC3C557508BA1002EC3CAA9E
-:105620007403E82FF6C3BA0402B01AEEB020EEB04D
-:1056300030EEB040EEB080EEBA0002B013EEB0072C
-:10564000EEBA0802B080EEBA0202B0BBEEBA0402B3
-:10565000B005EEC3C606CA1301C706F8790000C636
-:1056600006F67901C706D0790000C706D279000096
-:10567000C706D4790000C706FA790000C706FC798E
-:105680000000C706FE790000C706007A0000C706C2
-:10569000027ACE598C0E047AC706067A0000C70635
-:1056A000277A0000C606297A00C6062A7A00C39027
-:1056B000BE224DE8C80AE83F002C313C0177F7E8EC
-:1056C00081098B360C7AE8B50ABE6A4DE8AF0A0E3E
-:1056D00058E8F80ABE7A4DE8A40AC39060D1E38383
-:1056E000FB1873111EBA00008EDA2EFF97B7518B8C
-:1056F000EC8946101F61CF90E84F0B0AC07505E892
-:10570000560BEBF4C390833EF879017416BED7793B
-:10571000E8310A8BD0AC3C2C74043C207505E8239E
-:105720000AEEC3E9D2FE833EF8790174F6BED7795A
-:10573000E8110A8BD0AC3C2C74083C207404E9B707
-:10574000FE90E8FF09EFC3908B16067A833EF87946
-:1057500001740BBED779E8EB098BD0A3067AB02091
-:10576000E8570B8B16067AECE86F0BC38B16067A9C
-:10577000833EF87901740BBED779E8C7098BD0A3B3
-:10578000067AB020E8330B8B16067AEDE8670BC378
-:10579000FAC606F67900C390C606F67901FBC390F7
-:1057A00006E85809B020E8110B268B05E8470BB036
-:1057B00008E8060BE8030BE8000BE8FD0AB8010057
-:1057C000E8CFF4BA0202EC24017502EBDCBA06025F
-:1057D000EC07C390C706087A1000EB06C706087AE4
-:1057E0000100068E06FC798B3EFA79E80E09E80B7B
-:1057F00000893EFA798C06FC7907C390BEB24DE869
-:105800007C098B16087A52E82A09E80F0AE80C0A84
-:1058100033DBB9100090268A01E8BC09E8FD094392
-:10582000E2F4E8F709E8F40933DBB9100090268ABE
-:10583000013C2072053C7E760390B02EE8E30943DC
-:10584000E2ECBEB24DE8360983C7105A4A75B7C3B9
-:10585000068E06007A8B3EFE79E8A008893EFE7926
-:105860008C06007A578B360E7AE81209C706087A3A
-:105870001000BA0002E8E800E881FF5FBA0000E823
-:10588000DE00BEB54DE8F6088CC0E83F09B03AE846
-:1058900090098BC7E83509E87E08E8C30090E8B7AF
-:1058A00009E8A6090AC074F63C0B750683EF10EBF5
-:1058B00019903C0A750683C710EB0F903C0C7504D9
-:1058C00047EB07903C0875244F908B36FE798BC7C9
-:1058D0002BC63D000172A53D1001720483EE20909D
-:1058E00083C6108936FE79578BFEEB803C2E7508F7
-:1058F000BA0113E86A0007C3C6060A7A0232C990E1
-:105900003C30724C3C39760C245F3C4172423C4640
-:10591000773E2C072C3050E8CC085802C8FE0E0AFF
-:105920007A740FC0E104E82F09E81E090AC074F672
-:10593000EBCE26880DE8E0078AD0E823008AC13C38
-:105940002072053C7E760390B02EE8D508E970FF02
-:10595000E8C507E80A00268A05E87C08E91DFF90EB
-:10596000F606267A02750286F2528B361A7AE80D0E
-:10597000085A528AC60206247AF606267A01750665
-:10598000E89F08EB0D9032E4E80D088B361C7AE8AE
-:10599000EC075A8AC20206257AF606267A017506AF
-:1059A000E87F08EB069032E4E8ED078B361E7AE8D4
-:1059B000CC07C390068E06047A8B3E027AE83C0739
-:1059C000893E027A8C06047A07FF1E027AC3BE97CC
-:1059D0004DE8AA07CB900657BED779E866078BD863
-:1059E000E861078BC82BCB78118EC3BF0000B8FFCE
-:1059F000FF51B90800F3AB59E2F75F07C39006BE49
-:105A0000D779E83F078BD8D1E32E8B9F4400BE2681
-:105A100052E8F1088BC3E8DD08B80100E873F2E84A
-:105A2000E008BE2F52E8DD088B4718E8C808BE77AB
-:105A300052E8D1088B4726E8BC08BE5352E8C50897
-:105A40008B471EE8B008BE5C52E8B9088B4720E8D7
-:105A5000A408BE6E52E8AD088B4724E89808BE80C3
-:105A600052E8A1088B472AE88C08E89508BE38520E
-:105A7000E892088B07E87E08BE4152E887088B470A
-:105A80001AE87208BE4A52E87B088B471CE8660891
-:105A9000BE6552E86F088B4722E85A08E86308BEE3
-:105AA000D152E860088B4738E84B08BEAD52E85445
-:105AB000088B4730E83F08BEB652E848088B4732AB
-:105AC000E83308BEA452E83C088B472EE82708BEFE
-:105AD000BF52E830088B4734E81B08E82408BE8929
-:105AE00052E821088B4704E80C08BE9252E81508DA
-:105AF0008B4714E80008BE9B52E809088B472CE846
-:105B0000F407BEC852E8FD078B4736E8E807BEDA5F
-:105B100052E8F1078B473AE8DC07BEE352E8E507B5
-:105B20008B473CE8D007E8D907BE1953E8D6078B66
-:105B30004748E8C107BEFE52E8CA078B4742E8B5AE
-:105B400007BE0753E8BE078B4744E8A907BE7C534E
-:105B5000E8B2078B474CE89D07BE8553E8A6078B44
-:105B6000474EE89107BE8E53E89A078B4750E88569
-:105B700007E88E07BE2253E88B078B474AE8760773
-:105B8000BEEC52E87F078B4708E86A07BEF552E88B
-:105B900073078B4740E85E07BE1053E867078B47E3
-:105BA00046E85207E85B07BE6A53E858078B477A16
-:105BB000E84307BE3D53E84C078B4770E83707BE04
-:105BC0004653E840078B4772E82B07BE4F53E83433
-:105BD000078B4774E81F07E82807BE2B53E8250703
-:105BE0008B470CE81007BE3453E819078B4710E8C1
-:105BF0000407BE5853E80D078B4776E8F806BE61E8
-:105C000053E801078B4778E8EC06BE7353E8F506C6
-:105C10008B473EE8E006E8E906BE9753E8E6068BC8
-:105C20004752E8D106BEA053E8DA068B4754E8C5D0
-:105C300006BEA953E8CE068B4756E8B906BEB25356
-:105C4000E8C2068B4758E8AD06BEBB53E8B6068BE4
-:105C5000475AE8A106BEC453E8AA068B475CE895FC
-:105C600006E89E06BECD53E89B068B475EE8860697
-:105C7000BED653E88F068B4760E87A06BEDF53E84E
-:105C800083068B4762E86E06BEE853E877068B47CB
-:105C90007CE86206BEF153E86B068B477EE8560649
-:105CA000BEFA53E85F068B878000E84906E8520693
-:105CB000BE4254E84F068B879E00E83906BE035467
-:105CC000E842068B4764E82D06BE0C54E836068B86
-:105CD000476EE82106BE1554E82A068B878E00E839
-:105CE0001406BE1E54E81D068B879000E80706BE0A
-:105CF0002754E810068B879200E8FA05E80306BEF1
-:105D00003054E800068B879400E8EA05BE3954E871
-:105D1000F3058B879600E8DD05BE6F54E8E6058B3A
-:105D2000879800E8D005BE5D54E8D9058A87A000B1
-:105D3000E8A705BE5454E8CC058A4728E89B05BE71
-:105D40006654E8C0058A87A100E88E05E8B305BE61
-:105D50007854E8B0058A87A200E87E05BE8154E841
-:105D6000A3058A87A300E87105BE8A54E896058AD0
-:105D700087A400E86405BE9354E889058A87A500D6
-:105D8000E85705BE9C54E87C058A87A600E84A05CA
-:105D9000BEA554E86F058A87A700E83D05BEAE544E
-:105DA000E862058A87A800E83005E85505BEB754C3
-:105DB000E852058A87A900E82005BEC054E84505D9
-:105DC0008A87AA00E81305BEC954E838058A87AB5C
-:105DD00000E80605BED254E82B058A87AD00E8F935
-:105DE00004BEDB54E81E058A87AE00E8EC04BEE47E
-:105DF00054E811058A87AF00E8DF04BEED54E804DB
-:105E0000058A87B000E8D204E8F704BEF654E8F447
-:105E1000048A87B100E8C204BEFF54E8E7048A8719
-:105E2000B200E8B504BE0855E8DA048A87B300E892
-:105E3000A804BE1155E8CD048A87BB00E89B04E89E
-:105E4000C004BE1A55E8BD048A87BC00E88B04BEB6
-:105E50002355E8B0048A87BE00E87E04BE2C55E8CE
-:105E6000A3048A87BF00E87104E8960407C36006AC
-:105E70001E168BECFF4E16F7461A00027401FBB893
-:105E800000008ED88EC0892E2D7AE8CB0081661A4C
-:105E9000FFFEC6062A7A00E8D800B8005FA32B7A76
-:105EA000E85D00803E2A7A00740A814E1A0001C61D
-:105EB000062A7A00171F0761CF9060061E168BEC2A
-:105EC000F7461A00027401FBB800008ED88EC08914
-:105ED0002E2D7A81661AFFFEC6062A7A00E8920005
-:105EE000B8005FA32B7AE81700803E2A7A00740A74
-:105EF000814E1A0001C6062A7A00171F0761CF904B
-:105F0000B8F000E88CEDFF262B7AC390065356803C
-:105F10003E297A007403E83F00BED779E825028B5A
-:105F2000D8A3277A2E8A07A2297AB0CC2E88075EBA
-:105F30005B07C3C6062A7A00B80A5FA32B7AC39010
-:105F40008B2E2D7AE82B00C3C6062A7A01E80800BA
-:105F5000B80A5FA32B7AC39057803E297A00740F4A
-:105F60008B3E277AA0297A2E8805C606297A005FFB
-:105F7000C390BEB24DE80602BED851E80002FF76DB
-:105F80001458E84702BEDE51E8F301FF760E58E8E8
-:105F90003A02BEE451E8E601FF761258E82D02BE4F
-:105FA000EA51E8D901FF761058E82002BE1452E801
-:105FB000CC01FF760A58E81302BE1A52E8BF01FF6F
-:105FC000760C58E80602BECF51E8B201FF761A58A7
-:105FD000E8F901BEB24DE8A501BEF051E89F01FF0E
-:105FE000761858E8E601BEF651E89201FF760258AD
-:105FF000E8D901BEFC51E88501FF760458E8CC01E0
-:10600000BE0252E87801FF760058E8BF01BE085290
-:10601000E86B01FF760658E8B201BE0E52E85E0159
-:10602000FF760858E8A501BE2052E85101FF761618
-:1060300058E89801BE894DE84401C390BEC94DE8B7
-:106040003C01C33C0074053C017459C3C7060C7A7B
-:10605000CD50C7060E7AF050C706107AE850C70632
-:10606000127AEC50C706147AF450C706167AFB5021
-:10607000C706187A0351C7061A7A0B51C7061C7A4D
-:106080000E51C7061E7A1051C706207A1251C70654
-:10609000227A1651C606247A01C606257A01C6065A
-:1060A000267A03C3C7060C7A1A51C7060E7A4D51D9
-:1060B000C706107A4751C706127A4A51C706147AA2
-:1060C0004F51C706167A5151C706187A5551C7065F
-:1060D0001A7A5651C7061C7A5951C7061E7A5A5168
-:1060E000C706207A5B51C706227A5E51C606247A1B
-:1060F00020C606257A20C606267A02C3A1F879486A
-:106100007414BED779E83C008BF8AC3C3A75078E26
-:10611000C7E830008BF8C3908BC72B06FE798AF056
-:10612000240F8AD002D002D080C20BC0EE0480C6F9
-:1061300003043DC38CC0E89300B03AE8E4008BC789
-:10614000E88900C35133C990AC3C2074FB900AC06D
-:1061500074262C3072223C0976143C11721A2C07DA
-:106160003C0F760A3C2A72102C203C0F770A98C10B
-:10617000E10403C8ACEBD7904E8BC159C390068C99
-:10618000C88EC0E8020007C3268A04460AC0740607
-:10619000E88F00EBF390C3900BC0747A5133D2B9FF
-:1061A000E803F7F18BCAE803008BC159BA6400F623
-:1061B000F2E80C008AC498B20AF6F2E802008AC437
-:1061C000500AF074050430E8580058C386C4E80744
-:1061D0000086C4E80200C390C1C804E80800C1C03A
-:1061E00004E80200C3905350240FBBCA622ED7E8C4
-:1061F0003000585BC39086C4E8070086C4E80200FC
-:10620000C39050B908008AE032C0D1C00430E81110
-:1062100000E2F558C390B030E80700C3B020E801B1
-:1062200000C3568B36D0798884D0774681E6FF014B
-:10623000FF06D4798936D079813ED479FE0175087C
-:1062400056E814005EEBF1905EC3BA0202EC240142
-:106250007404BA0602ECC390803EF67900740960BB
-:10626000B80100E82CEA6190BA0202ECA804742894
-:106270008B36D279833ED47900741D8A84D07746D8
-:1062800081E6FF018936D279FF0ED479BA0602EE93
-:10629000BA0202ECA80475DCA1D479C352BA060292
-:1062A000EE5AC3905250BA0202ECA8047408585A2D
-:1062B000E8E9FFF9C390585AF8C35250BA0202EC09
-:1062C000A80474FB585AE8D3FFC330313233343555
-:1062D0003637383941424344454653508AE080E4DA
-:1062E0000FBBCA62C0E8042ED7E8CEFF8AC42ED7FF
-:1062F000E8C7FF585BC386E0E8DFFF86E0E8DAFF27
-:10630000C390BEB24D502EAC3C007405E8ABFFEB21
-:10631000F558C390C808000056578B7604BF040098
-:10632000C746FC0000C746FA0000C746F8000083D5
-:106330007E0600750E56E8B60E590BC075058BC764
-:10634000E95B018B46FC8946FE0BFF7505B8010031
-:10635000EB0233C05056E8A40D5959B4008946FCED
-:106360008B5EFC83FB087603E92B01D1E32EFFA7AC
-:10637000B264B80300E92601837EFA007414C746AC
-:10638000FA00008A445898508A44599850E8C20F3D
-:106390005959837EF800740AC746F8000056E89BF6
-:1063A0000859837E060075058BC7E9F10083FF0459
-:1063B0007503E9E6008BC7E9E400837EFE00750300
-:1063C000BF0200E9D500837EFE007503BF0100E92E
-:1063D000C9008B5EFE83FB077603E98600D1E32EBE
-:1063E000FFA7A26433FFE97F00BF0400807C580F41
-:1063F0007422837EF800751CFE44586A0856E87EB5
-:106400000C59598A445804805056E8720C5959C79F
-:1064100046FA0100837EF800740AC746F800005669
-:10642000E8190859EB42BF0400807C5800742283AD
-:106430007EF800751CFE4C586A0856E8410C595904
-:106440008A445804805056E8350C5959C746FA0119
-:1064500000837EF800740AC746F8000056E8DC079F
-:1064600059EB05BF0400EB00EB31BF0400EB2CC778
-:1064700046F801006A0856E8050C5959807C58090D
-:106480007D04B00FEB02B00004805056E8F00B59C9
-:1064900059BF0400EB05BF0400EB00E9A5FE5F5EF9
-:1064A000C9C3E4636364636463646364E963266427
-:1064B00051647863BA63C6639664D2636A646A643B
-:1064C0006F647263C808000056578B76048B7E0891
-:1064D0006A0156E8A90B59598A4606C0E0060480AD
-:1064E0005056E89A0B5959C746FE0000897EF8EBD2
-:1064F00003FF46FE8B5EF8FF46F8803F0075F2838F
-:106500007EFE107D25B810002B46FED1F88946FC92
-:10651000C746FA0000EB0B6A2056E8620B5959FF98
-:1065200046FA8B46FA3B46FC7CEDEB0C8BDF478A48
-:10653000075056E8490B5959803D0075EF6A0256DD
-:10654000E83C0B5959EB005F5EC9C3C80400005614
-:10655000578B7E04C746FE0000BE1400E909018B7C
-:106560005EFE83C3042BDF8A87AC0B88445AC64483
-:1065700058088A46FE884459C744060000C6441994
-:1065800000C6441A00C6441B00C6441D0DC6441E66
-:1065900003C6441F00C6442000C6442100C6445B15
-:1065A00000C6445D00C6445E00C6445F00C6446049
-:1065B00000C746FC0000EB0D8B5EFCD1E3C740300A
-:1065C0000000FF46FC837EFC107CEDC746FC00000B
-:1065D000EB0A8B5EFCC6405000FF46FC837EFC0449
-:1065E0007CF0C744540000C7445600008A445A98BF
-:1065F000BAF80023D0B805000BC28946FC9CFA8A81
-:1066000046FCBAFE00EEBA0000EC9D24088846FC69
-:10661000837EFC007502EB4AFF76FEE87A0C59682F
-:10662000350256E8320A59590BC07534683802569B
-:10663000E8250A59590BC0752768420256E8180A1E
-:1066400059590BC0751A684C0256E80B0A59590B78
-:10665000C0750D68560256E8FE0959590BC0740200
-:10666000EB00FF46FE83C662397EFE7D03E9EFFE46
-:10667000EB005F5EC9C3C808000056578B4604BADA
-:106680006200F7EA0514008BF0837E06007405B8FB
-:106690001000EB03B808008944048A460888445C6B
-:1066A00056E85904598BF88BC78944568944548A53
-:1066B000445D88442F0BFF751D68C20F6A0156E8C0
-:1066C00002FE83C406EB006A0156E847FC59590BE9
-:1066D000C075F4BF0100897EFAB90500BBE96A2ED6
-:1066E0008B073B46FA74074343E2F4E9A4032EFF09
-:1066F000670AC744060200C74408F4088B5E04D149
-:10670000E38B87FC0889440A33C08BF8894454E939
-:10671000800356E8BB0559BF01008A445D88446088
-:10672000E96F03837C04087530807C5C0175158AF1
-:10673000445DB400D1E08BD8FFB7E40856E8F70811
-:106740005959EB138A445DB400D1E08BD8FFB7C42C
-:106750000856E8E2085959EB2E807C5C0175158AD1
-:10676000445DB400D1E08BD8FFB7D40856E8C70821
-:106770005959EB138A445DB400D1E08BD8FFB7B40C
-:106780000856E8B20859596A0156E887FB59598BEF
-:10679000D883FB03772AD1E32EFFA7E16ABF01006C
-:1067A0008A445D88445EEB188A445D04FF240788B0
-:1067B000445DEB0C8A445DFEC0240788445DEB0019
-:1067C000E9CF028A445DB400D1E08BD8FFB7FD0267
-:1067D00056E863085959681D0356E85A0859596A1A
-:1067E0000156E82FFB59598BD883FB037736D1E349
-:1067F0002EFFA7D96ABF01008A445D88445FEB245D
-:106800008A445D04FF8A540480C2FF22C288445D2A
-:10681000EB128A445DFEC08A540480C2FF22C28803
-:10682000445DEB00E96B028B5C0683C3FED1E38B16
-:10683000400889048B1CFF77066A0056E885FC83B4
-:10684000C4068B5C064BD1E38B40088944028B5C09
-:1068500002FF77066A0156E86AFC83C4066A01569D
-:10686000E8B1FA59598BD883FB037603E91F02D1AB
-:10687000E32EFFA7D16A8B5C028B47048944028B0D
-:106880005C02803F44750D8B5C028A4701B4003B7B
-:1068900044047DE28B4604D1E08B1C03D88B440278
-:1068A0008947088B5C064BD1E38B4402894008E999
-:1068B000DE018B5C028B47028944028B5C02803FC5
-:1068C00044750D8B5C028A4701B4003B44047DE2B1
-:1068D0008B4604D1E08B1C03D88B44028947088B7C
-:1068E0005C064BD1E38B4402894008E9A201BF0159
-:1068F00000E99C018B5C028A07B4008946F8B90C58
-:1069000000BBA16A2E8B073B46F874074343E2F4B1
-:10691000E977012EFF67188B4604D1E08B5C0203F8
-:10692000D88B47088B5C06FF4406D1E38940088B6F
-:106930001C807F010074128B5C028A47018B1C8AC9
-:106940005701B6008BDA884018E94001FF4C06E990
-:106950003A018B5C028A47018B1C8A5701B6008B77
-:10696000DA884018E925018B5C028A47018B1C8A72
-:106970005701B6008BDA884018FF4C06E90D018BF1
-:106980005C028A47018B1C8A5701B6008BDA3040C3
-:1069900018E9F800B8F0108BF88944548A445F88ED
-:1069A000445DE9E7008A441C983D020074073D03FA
-:1069B000007402EB07C746FE0000EB2B8A441C98CC
-:1069C000D1E08BD8FFB7690256E86B0659596A01C6
-:1069D00056E840F959598946FE837EFE00740683C5
-:1069E0007EFE0375E9EB00837EFE0374628A441C1D
-:1069F00098D1E08BD8FFB76D0256E83A0659595640
-:106A0000E84D97598946FC8B5EFC83EBFE83FB03C4
-:106A10007733D1E32EFFA7996A68AC0256E81706D0
-:106A20005959EB23688F0256E80C065959EB186840
-:106A3000750256E801065959EB0D68C60256E8F68C
-:106A4000055959EB02EB006A0156E8C7F85959BFDE
-:106A50000100EB3868DD0256E8DC0559596A015639
-:106A6000E8B1F85959BF0100EB22B8D0308BF88952
-:106A700044548A446088445DEB12B8E0208BF88966
-:106A800044548A445E88445DEB02EB00EB02EB0069
-:106A9000EB00E941FC5F5EC9C3196A246A2F6A3AB8
-:106AA0006A0000010002000400410042004300446B
-:106AB00000800081008200FF001769546A7A6AA58D
-:106AC00069526994696A6A676952697F6967694C42
-:106AD00069F4687668B268EE68F56700681268F570
-:106AE000679D67A867B4679D6700000100F010E02C
-:106AF00020D0302768F266C36723671267C8040096
-:106B00000056578B76048A4459988946FC6A098B4B
-:106B100046FC05840150E8930859598BF88BC7252A
-:106B200000F03D001075558BC725F0003DF0007555
-:106B30004B8BC725000FC1F8088946FE8B44043BE8
-:106B400046FE7D0533C0E9EF008BC7250F00BA0F65
-:106B5000002BD03B56FE740533C0E9DB00C744026E
-:106B600004098A46FE88445F88445D8B5EFCD1E35D
-:106B7000C787FC080409B8F010E9BC008BC72500E2
-:106B8000F03D002075528BC725F0003DE0007548B0
-:106B90008BC725000FC1F8088946FE837EFE087E5C
-:106BA0000533C0E992008BC7250F00BA0F002BD028
-:106BB0003B56FE740533C0EB7F90C744020C098A34
-:106BC00046FE88445E88445D8B5EFCD1E3C787FC4B
-:106BD000080C09B8E020EB608BC72500F03D0030C1
-:106BE00075528BC725F0003DD00075488BC7250036
-:106BF0000FC1F8088946FE8B44043B46FE7D0433F2
-:106C0000C0EB358BC7250F00BA0F002BD03B56FECB
-:106C1000740433C0EB22C7440214098A46FE884438
-:106C20006088445D8B5EFCD1E3C787FC081409B81B
-:106C3000D030EB0433C0EB005F5EC9C3C806000070
-:106C4000568B76046A0856E8350459598A44580424
-:106C5000805056E8290459598B44543B4456750AD0
-:106C60008A445D3A442F7502EB648B445489445640
-:106C70008B5C028A470188442F8A445DB400C1E0DE
-:106C8000088B54540BD08A445DB400BB0F002BD842
-:106C90000BD38956FE6A108A445998050400990559
-:106CA000400183D2005250E8540883C4068956FC40
-:106CB0008946FA8B46FE0946FA834EFC006A19FFA4
-:106CC00076FCFF76FAE8730783C406E8FE075EC920
-:106CD000C3C81C000056578B5E048A4759988BF036
-:106CE0008B5E048A475DB4008946E6837EE6007DBC
-:106CF0000A8B5E048B4704488946E68B5E048B470B
-:106D0000043B46E67F05C746E600008B5E048A46E4
-:106D1000E688475D8BDED1E38B9F5902C647022090
-:106D20008BDED1E38B9F5902C64703308BDED1E364
-:106D30008B9F6102C64702208BDED1E38B9F6102ED
-:106D4000C64703308B46E68946FA837EFA007418FC
-:106D50008B46FABB0A0033D2F7F380C2308BDED108
-:106D6000E38B9F5902885703BB0A008B46FA33D244
-:106D7000F7F38946FA837EFA0074188B46FABB0A49
-:106D80000033D2F7F380C2308BDED1E38B9F590200
-:106D90008857028B46E68946FA837EFA0074188B80
-:106DA00046FABB0A0033D2F7F380C2308BDED1E360
-:106DB0008B9F6102885703BB0A008B46FA33D2F7D8
-:106DC000F38946FA837EFA0074188B46FABB0A00F0
-:106DD00033D2F7F380C2308BDED1E38B9F61028820
-:106DE00057028B5EE6D1E3FFB712026A00FF76041A
-:106DF000E8D1F683C40668D30F6A01FF7604E8C3BE
-:106E0000F683C406FF76E656E8019359598956F28F
-:106E10008946F0FF76E656E8149359598956EE896B
-:106E200046EC9CFAC45EF0268B078946EAC45EEC09
-:106E3000268B078946E8BA50FFED8946FE9DC74676
-:106E4000E40100E8EEA0BA50FFED8946FC8B46FC59
-:106E50002B46FE3DE8037303E980019CFABA50FF1C
-:106E6000ED8946FC8B46FC2B46FE8946F8C45EF055
-:106E7000268B072B46EA8946F6C45EF0268B0789E7
-:106E800046EAC45EEC268B072B46E88946F4C45ECE
-:106E9000EC268B078946E8BA50FFED8946FE9D81B6
-:106EA0007EF8E803761CFF76F8FF76F6E87601595F
-:106EB000598946F6FF76F8FF76F4E8680159598952
-:106EC00046F4BF0E00EB178BDED1E38B9F5902C651
-:106ED00001208BDED1E38B9F6102C601204783FF37
-:106EE0001176E48BDED1E38B9F5902C6470D308BC0
-:106EF000DED1E38B9F6102C6470D30837EF60977B2
-:106F000005B80D00EB26837EF6637705B80E00EB1F
-:106F10001B817EF6E7037705B80F00EB0F817EF645
-:106F20000F277705B81000EB03B811008BF8EB259D
-:106F30008B46F6BB0A0033D2F7F380C2308BDED12A
-:106F4000E38B9F590288114FBB0A008B46F633D260
-:106F5000F7F38946F6837EF60075D5837EF40977CC
-:106F600005B80D00EB26837EF4637705B80E00EBC1
-:106F70001B817EF4E7037705B80F00EB0F817EF4E9
-:106F80000F277705B81000EB03B811008BF8EB253D
-:106F90008B46F4BB0A0033D2F7F380C2308BDED1CC
-:106FA000E38B9F610288114FBB0A008B46F433D2FA
-:106FB000F7F38946F4837EF40075D58BDED1E3FFC9
-:106FC000B75902FF7604E86E0059598BDED1E3FF12
-:106FD000B76102FF7604E85E0059596A00FF760443
-:106FE000E831F359598BD883FB04771FD1E32EFF87
-:106FF000A71B70EB22C746E40000FF4EE6EB0CC770
-:1070000046E40000FF46E6EB02EB00837EE40074FA
-:1070100003E92AFEE9D4FC5F5EC9C3F36FF56FFF95
-:107020006FF36F0970558BEC8B4604B9E803F7E1F9
-:107030008B4E06F7F15DC3558BEC568B7606EB0E47
-:107040008BDE468A0750FF7604E833005959803CAE
-:107050000075EDEB005E5DC3558BEC568B7606EB51
-:10706000148BDE468A0750FF7604E8450059590B19
-:10707000C07402EB07803C0075E7EB005E5DC3C89F
-:10708000020000568B76048A445A988946FE9CFA80
-:107090008A46FEBAFE00EEBA0200ECA80274069D13
-:1070A000E8919EEBE9BA00008A4606EE9DEB005E91
-:1070B000C9C3C8040000568B76048A445A9889468E
-:1070C000FEE8E6A18946FCE8E0A12B46FC3DB80BB2
-:1070D0007605B80100EB239CFA8A46FEBAFE00EE64
-:1070E000BA0200ECA80274069DE8489EEBD9BA00EB
-:1070F000008A4606EE9D33C0EB005EC9C3C804009B
-:107100000056578B7604837E0600740756E8030109
-:1071100059EB0556E8A200598846FF807EFF0877A4
-:10712000068A46FFE98400807EFF0F7603EB7990A4
-:107130008A46FFB4002D0A008BD883FB047767D101
-:10714000E32EFFA7AF71B000EB6156E86B0059B4B6
-:1071500000250F008946FC56E85E0059B4008BF804
-:1071600056E8550059B400C1E0088BD703D08BFA1C
-:107170008B5EFCD1E3897830EB2E56E83B005988D2
-:10718000445BEB2456E831005988445056E8290006
-:107190005988445156E821005988445256E819004C
-:1071A00059884453EB02EB00E95BFF5F5EC9C346BD
-:1071B00071A6714A717A718471C8040000568B7689
-:1071C000048A445A988946FE9CFA8A46FEBAFE0012
-:1071D000EEBA0200ECA80175069DE8579DEBE9BAEE
-:1071E0000000EC8846FD9D8A46FDEB005EC9C3C8E1
-:1071F000020000568B76048A445A988946FE9CFA0F
-:107200008A46FEBAFE00EEBA0200EC32E424019D8A
-:107210005EC9C3C8060000568B76048A445A988912
-:1072200046FEE885A08946FAE87FA02B46FA3DB8DD
-:107230000B7604B008EB249CFA8A46FEBAFE00EEF8
-:10724000BA0200ECA80175069DE8E89CEBDABA00EA
-:1072500000EC8846FD9D8A46FDEB005EC9C3558B58
-:10726000EC568B56048A4606EE33F6EB035058462E
-:1072700083FE147CF85E5DC3C8020000568B560482
-:10728000EC8846FF33F6EB0350584683FE147CF837
-:107290008A46FFEB005EC9C3C802000056578B76D2
-:1072A00004833EB00B00751FBA8801B000EEBA86A9
-:1072B00001B000EE6A096A00683001E87D0183C40C
-:1072C00006C706B00B01006A098BC605800150E8AD
-:1072D000DA0059598BF88BC7C1E80C250F00894695
-:1072E000FE8BC7C1E808250F008B56FE83F20C3BCE
-:1072F000C275218BC7C1E804250F008B56FE83F2AF
-:10730000063BC2750F8BC7250F008B56FE83F20913
-:107310003BC2740D6A0756E838005959C746FE0744
-:10732000008A46FE0480A233028BC6BA6200F7EAE6
-:107330008A56FE8BD888976C006832028BC6BA6278
-:1073400000F7EA05140050E80EFD5959EB005F5EA6
-:10735000C9C3C8020000568B760683E60F8BC6C1F0
-:10736000E00C8BD683F20CC1E2080BC28BD683F201
-:1073700006C1E2040BC28BD683F2090BC28946FE1A
-:107380006A196A108B46049905400183D200525055
-:10739000E86B0183C4060B46FE83CA005250E89A8C
-:1073A0000083C406E82501EB005EC9C3558BEC568B
-:1073B0005733FF6A01688601E8A3FE5959B1102AC4
-:1073C0004E06D3660433F6EB2E817E0400807204F1
-:1073D000B001EB02B00050688801E881FE59596A9B
-:1073E00003688601E877FE59596A01688601E86DED
-:1073F000FE5959D16604463B76067CCD33F6EB2424
-:10740000D1E76A03688601E854FE59596A01688623
-:1074100001E84AFE5959688801E85CFE599825013F
-:10742000000BF84683FE107CD76A00688601E82DC1
-:10743000FE59598BC7EB005F5E5DC3558BEC565709
-:107440008B7E086A01688601E813FE5959B820004E
-:107450002BC750FF7606FF7604E8A20083C4068996
-:10746000560689460433F6EB47817E060080720C8F
-:107470007506837E04007204B001EB02B000506810
-:107480008801E8D9FD59596A03688601E8CFFD599A
-:10749000596A01688601E8C5FD59596A01FF7606F7
-:1074A000FF7604E8580083C40689560689460446D8
-:1074B0003BF77CB56A00688601E8A2FD59596A006D
-:1074C000688601E898FD59595F5E5DC3558BEC569F
-:1074D0006A01688601E886FD595933F6EB00688831
-:1074E00001E894FD59A80175088BC6463D64007CEF
-:1074F000ED6A00688601E865FD59595E5DC3C80400
-:1075000000008B46048B56068B4E08E306D1E0D173
-:10751000D2E2FA8946FC8956FE8B56FE8B46FCEB7E
-:1075200000C9C300000000000000000000000000CF
-:1075300050726576696F7573204D656E7500426592
-:1075400067696E00000000000000000000000000FD
-:10755000000000000000000000000000000000002B
-:10756000000000000000000000000000000000001B
-:10757000000000000000000000000000000000000B
-:1075800000000000000000000000000000000000FB
-:1075900000000000000000000000000000000000EB
-:1075A00000000000000000000000000000000000DB
-:1075B00000000000000000000000000000000000CB
-:1075C00000000000000000000000000000000000BB
-:1075D00000000000000000000000000000000000AB
-:1075E000000000000000000000000000000000009B
-:1075F000000000000000000000000000000000008B
-:10760000000000000000000000000000000000007A
-:10761000000000000000000000000000000000006A
-:10762000000000000000000000000000000000005A
-:10763000000000000000000000000000000000004A
-:10764000000000000000000000000000000000003A
-:10765000000000000000000000000000000000002A
-:10766000000000000000000000000000000000001A
-:10767000000000000000000000000000000000000A
-:1076800000000000000000000000000000000000FA
-:1076900000000000000000000000000000000000EA
-:1076A00000000000000000000000000000000000DA
-:1076B00000000000000000000000000000000000CA
-:1076C000000000000000000000000000506F727415
-:1076D000203000506F7274203100506F727420326D
-:1076E00000506F7274203300506F72742034005059
-:1076F0006F7274203500506F7274203600506F72B4
-:1077000074203700506F7274203800506F727420EC
-:107710003900506F727420313000506F7274203114
-:107720003100506F727420313200506F727420310A
-:107730003300506F727420313400506F72742031F6
-:1077400035009C01A301AA01B101B801BF01C60126
-:10775000CD01D401DB01E201EA01F201FA010202EA
-:107760000A02080000078100038080809F919591A4
-:107770009F000381848E95848484840003828484A2
-:107780008484958E8400048800B20BC60BDA0BEE5D
-:107790000B020C160C2A0C3E0C520C770C9C0CBEE7
-:1077A0000CE00C020D01802054657374205061734D
-:1077B000736564201F20507265737320800200017E
-:1077C00080204D697373696E67205278204461741C
-:1077D000611F205072657373208002000180204277
-:1077E00061642052782044617461201F20507265CA
-:1077F000737320800200018020586D7472204275DE
-:1078000073791F20507265737320800200018020FD
-:107810006E6F742063757272656E746C791F2020B0
-:10782000696D706C656D656E7465640200240D2F62
-:107830000D3A0D450D500D5B0D660D710D7C0D87DC
-:107840000D920D9D0DA80DB30DBE0DC90D53802CCD
-:107850003254442053862C334454522053822C33C8
-:10786000525453201F53812C3252442053852C32C2
-:1078700043442053832C334354532053842C3344A8
-:1078800053522053872C3252492702000180202076
-:10789000444344202D2070696E2032301F275385C9
-:1078A0002E31818263908081828384858687888956
-:1078B0008A8B8C8D8E8F27020001802020445352AA
-:1078C000202D2070696E2031311F2753842E318185
-:1078D000826390808182838485868788898A8B8C65
-:1078E0008D8E8F27020001802020435453202D20AD
-:1078F00070696E20341F2753832E318182639080FC
-:107900008182838485868788898A8B8C8D8E8F2758
-:107910000200018020205249202D2070696E203203
-:10792000321F2753872E3181826390808182838426
-:1079300085868788898A8B8C8D8E8F2702000180AF
-:107940002020445452202D2070696E20362F381F7D
-:107950002753862E3181826390808182838485863D
-:107960008788898A8B8C8D8E8F270200018020204A
-:10797000525453202D2070696E20351F2753822EBC
-:107980003181826390808182838485868788898A19
-:107990008B8C8D8E8F27020001802020527844200E
-:1079A0002D2070696E20321F2753812E30534D8158
-:1079B000826390808182838485868788898A8B8C84
-:1079C0008D8E8F27020001802020547844202D20A6
-:1079D00070696E20331F2753802E30534D81826390
-:1079E00090808182838485868788898A8B8C8D8E1E
-:1079F0008F27020001802020444344202D207069FD
-:107A00006E20351F2753852E3181826390808182BD
-:107A1000838485868788898A8B8C8D8E8F27020048
-:107A200001802020445352202D2070696E20351F84
-:107A30002753842E3181826390808182838485865E
-:107A40008788898A8B8C8D8E8F2702000180202069
-:107A5000435453202D2070696E20311F2753832EED
-:107A60003181826390808182838485868788898A38
-:107A70008B8C8D8E8F270200018020205249202D73
-:107A800020286E2E632E291F2753872E3181826373
-:107A900090808182838485868788898A8B8C8D8E6D
-:107AA0008F27020001802020445452202D2070692D
-:107AB0006E20321F2753862E31818263908081820F
-:107AC000838485868788898A8B8C8D8E8F27020098
-:107AD00001802020525453202D2070696E20371FC2
-:107AE0002753822E318182639080818283848586B0
-:107AF0008788898A8B8C8D8E8F27020001802020B9
-:107B0000527844202D2070696E20361F2753812E15
-:107B100030534D81826390808182838485868788FB
-:107B2000898A8B8C8D8E8F270200018020205478CB
-:107B300044202D2070696E20331F2753802E305330
-:107B40004D81826390808182838485868788898A3B
-:107B50008B8C8D8E8F27020001802020444344208F
-:107B60002D2070696E20351F202020202753852E60
-:107B700031818263888081828384858687270200A1
-:107B800001802020445352202D2070696E20351F23
-:107B9000202020202753842E318182638880818297
-:107BA0008384858687270200018020204354532048
-:107BB0002D2070696E20311F202020202753832E16
-:107BC0003181826388808182838485868727020051
-:107BD000018020205249202D20286E2E632E291F3F
-:107BE000202020202753872E318182638880818244
-:107BF00083848586872702000180202044545220F8
-:107C00002D2070696E20321F202020202753862EC1
-:107C10003181826388808182838485868727020000
-:107C200001802020525453202D2070696E20371F70
-:107C3000202020202753822E3181826388808182F8
-:107C40008384858687270200018020205278442083
-:107C50002D2070696E20361F202020202753812E72
-:107C600030534D8182638880818283848586872713
-:107C7000020001802020547844202D2070696E205D
-:107C8000331F202020202753802E30534D818263C4
-:107C90008880818283848586872702000180202056
-:107CA000444344202D2070696E2032301F20202054
-:107CB000202753852E318182638880818283848549
-:107CC000868727020001802020445352202D2070F7
-:107CD000696E2031311F202020202753842E3181CE
-:107CE0008263888081828384858687270200018061
-:107CF0002020435453202D2070696E20341F2020F3
-:107D000020202753832E318182638880818283845F
-:107D1000858687270200018020205249202D20706F
-:107D2000696E2032321F202020202753872E318178
-:107D30008263888081828384858687270200018010
-:107D40002020445452202D2070696E20362F381F79
-:107D5000202020202753862E3181826388808182D3
-:107D60008384858687270200018020205254532077
-:107D70002D2070696E20351F202020202753822E51
-:107D8000318182638880818283848586872702008F
-:107D900001802020527844202D2070696E20321FEF
-:107DA000202020202753812E30534D8182638880EC
-:107DB0008182838485868727020001802020547871
-:107DC00044202D2070696E20331F2020202027534F
-:107DD000802E30534D8182638880818283848586A2
-:107DE0008727020068049604B6033C040E04890346
-:107DF0005C03E20360088A08BE0738080E0895078E
-:107E00006C07E6071C057405FA05C404F004CC05EC
-:107E1000A00548057806C806420728065006180738
-:107E2000F006A0060000F408F408D40D04090409C3
-:107E30000409040942000C091C09E50D020014099B
-:107E40000409F40D43001C090C09050E0004040983
-:107E50001409120E2C092C092C092C0900003C09CC
-:107E60006C091E0E740974097409740900014C0927
-:107E70002C092D0E740974097409740900025C0937
-:107E80003C093D0E740974097409740900036C09F6
-:107E90004C094D0E7409740974097409FF002C090A
-:107EA0005C09000000058409EC095E0EF409F40980
-:107EB000F409F409000694097409680EAC0AAC0AC6
-:107EC000AC0AAC0A0007A4098409720EBC0ABC0AF9
-:107ED000BC0ABC0A0008B40994097C0ED40AD40A6E
-:107EE000D40AD40A000BC409A409830EFC0AFC0AB4
-:107EF000FC0AFC0A000CD409B409900E140B140BF4
-:107F0000140B140B0002E409C409A00E2C0B2C0B5B
-:107F10002C0B2C0B0400EC09D4090E00FF00740993
-:107F2000E40900008201FC09A40AAC0E8202040AE2
-:107F3000F409AF0E82030C0AFC09B20E8204140A83
-:107F4000040AB60E82051C0A0C0ABC0E8206240A1C
-:107F5000140AC00E82072C0A1C0AC40E8208340AB6
-:107F6000240AC80E82093C0A2C0ACC0E820A440A52
-:107F7000340AD10E82104C0A3C0AD60E820B540AE7
-:107F8000440ADB0E82115C0A4C0AE00E820C640A81
-:107F9000540AE50E82126C0A5C0AEA0E820D740A1B
-:107FA000640AEF0E820E7C0A6C0AF40E820F840AB9
-:107FB000740AFB0E82138C0A7C0A020F8214940A44
-:107FC000840A090F82159C0A8C0A100F8216A40AD3
-:107FD000940A170F8217F4099C0A1E0F8202B40A32
-:107FE000B40A260F8203AC0AAC0A2D0F8200C40A21
-:107FF000CC0A340F8201CC0ABC0A3F0F8202BC0AB1
-:10800000C40A4D0F8200DC0AF40A590F8201E40A07
-:10801000D40A630F8202EC0ADC0A6E0F8203F40AB0
-:10802000E40A7A0F8204D40AEC0A870F8200040B58
-:108030000C0B930F82010C0BFC0A9B0F8202FC0AB3
-:10804000040BA70F82001C0B240BB00F8201240B22
-:10805000140BB50F8202140B1C0BBE0F4400340B23
-:10806000A40B9C0144013C0B2C0BA3014402440BC8
-:10807000340BAA0144034C0B3C0BB1014404540BD8
-:10808000440BB80144055C0B4C0BBF014406640B68
-:10809000540BC60144076C0B5C0BCD014408740BF8
-:1080A000640BD40144097C0B6C0BDB01440A840B88
-:1080B000740BE201440B8C0B7C0BEA01440C940B17
-:1080C000840BF201440D9C0B8C0BFA01440EA40BA3
-:1080D000940B0202440F2C0B9C0B0A02171F0F2F4C
-:1080E0000000018078783A20747820637073202A29
-:1080F0002A2A2A2A0200018078783A20747820639C
-:108100007073202A2A2A2A2A0200018078783A20CD
-:10811000747820637073202A2A2A2A2A0200018098
-:1081200078783A20747820637073202A2A2A2A2AC1
-:10813000020001C078783A20726320637073202AAD
-:108140002A2A2A2A020001C078783A207263206322
-:108150007073202A2A2A2A2A020001C078783A203D
-:10816000726320637073202A2A2A2A2A020001C01F
-:1081700078783A20726320637073202A2A2A2A2A88
-:1081800002000180496E7374616C6C204C6F6F70DB
-:108190006261636B1F5072657373208020746F205F
-:1081A000737461727402000180204361626C652007
-:1081B000746F2052656D6F74651F50726573732004
-:1081C0008020746F20737461727402000180204CEF
-:1081D0006F63616C204C6F6F706261636B201F2056
-:1081E0002052756E6E696E67202E2E2E0200018061
-:1081F00052656D6F7465204C6F6F706261636B20A8
-:108200001F202052756E6E696E67202E2E2E020082
-:10821000018020496E74726E6C204C6F6F706261C9
-:10822000636B1F202052756E6E696E67202E2E2E96
-:10823000020001805472616E736D69742050617424
-:108240007465726E1F202052756E6E696E67202EE7
-:108250002E2E020001802020303A2027438000018A
-:10826000802020313A202743810001802020323AAB
-:10827000202743820001802020333A2027438300B7
-:1082800001802020343A20274384000180202035BB
-:108290003A202743850001802020363A2027438654
-:1082A0000001802020373A202743870001802020CA
-:1082B000383A202743880001802020393A2027437C
-:1082C000890001802031303A2027438A0001802034
-:1082D00031313A2027438B0001802031323A202768
-:1082E000438C0001802031333A2027438D000180E8
-:1082F0002031343A2027438E0001802031353A2046
-:1083000027438F002A2A204D61696E20204D656E1B
-:1083100075202A2A004D6F6E69746F72206120509B
-:108320006F7274004D6F6E69746F722061205369B3
-:10833000676E616C00457374696D617465204350AC
-:108340005300446961676E6F7374696373004C6FA7
-:1083500063616C204C6F6F706261636B0052656D7E
-:108360006F7465204C6F6F706261636B00496E744F
-:10837000726E6C204C6F6F706261636B005472613F
-:108380006E736D6974205061747465726E00426121
-:10839000756420526174650044617461204269749F
-:1083A000730053746F702042697473005061726976
-:1083B00074790044617461205061747465726E0058
-:1083C000547820466C6F7720436F6E74726F6C0028
-:1083D000506F7274204E756D6265720035300037D3
-:1083E0003500313130003133342E35003135300035
-:1083F00032303000333030003630300031323030FF
-:10840000003138303000323030300032343030001B
-:1084100033363030003438303000373230300039C5
-:108420003630300031392C3230300033382C343093
-:10843000300035362C3030300035372C36303000B7
-:1084400036342C3030300037362C38303000313173
-:10845000352C323030003720626974730038206266
-:1084600069747300312073746F7020626974003115
-:108470002E352073746F702062697473003220731C
-:10848000746F702062697473006E6F20706172691E
-:108490007479006F64642070617269747900657624
-:1084A000656E207061726974790073706163652014
-:1084B000706172697479006D61726B2070617269AC
-:1084C000747900436F6C756D6E7300426172626502
-:1084D0007220506F6C650055555555552E2E2E0047
-:1084E0004E6F6E6500586F6E2F586F66660043546E
-:1084F00053005072657373208020666F72206D6523
-:108500006E750028636F756E74696E672E2E2E2946
-:108510000000654E64204F6620436F4465000000F4
-:10852000000000000000000000000000000000004B
-:10853000000000000000000000000000000000003B
-:10854000000000000000000000000000000000002B
-:10855000000000000000000000000000000000001B
-:10856000000000000000000000000000000000000B
-:1085700000000000000000000000000000000000FB
-:1085800000000000000000000000000000000000EB
-:1085900000000000000000000000000000000000DB
-:1085A00000000000000000000000000000000000CB
-:1085B00000000000000000000000000000000000BB
-:1085C00000000000000000000000000000000000AB
-:1085D000000000000000000000000000000000009B
-:1085E000000000000000000000000000000000008B
-:1085F000000000000000000000000000000000007B
-:00000001FF
-/* Intelliport II loadware */
-/* -31232 bytes read from ff.lod */
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index debdfe0fc809..59f8db4a39a7 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -866,6 +866,12 @@ COMPATIBLE_IOCTL(TIOCGPTN)
COMPATIBLE_IOCTL(TIOCSPTLCK)
COMPATIBLE_IOCTL(TIOCSERGETLSR)
COMPATIBLE_IOCTL(TIOCSIG)
+#ifdef TIOCSRS485
+COMPATIBLE_IOCTL(TIOCSRS485)
+#endif
+#ifdef TIOCGRS485
+COMPATIBLE_IOCTL(TIOCGRS485)
+#endif
#ifdef TCGETS2
COMPATIBLE_IOCTL(TCGETS2)
COMPATIBLE_IOCTL(TCSETS2)
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index fa217607c582..c57e064666e4 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -84,7 +84,6 @@ header-y += capability.h
header-y += capi.h
header-y += cciss_defs.h
header-y += cciss_ioctl.h
-header-y += cdk.h
header-y += cdrom.h
header-y += cgroupstats.h
header-y += chio.h
@@ -93,7 +92,6 @@ header-y += cn_proc.h
header-y += coda.h
header-y += coda_psdev.h
header-y += coff.h
-header-y += comstats.h
header-y += connector.h
header-y += const.h
header-y += cramfs_fs.h
@@ -140,7 +138,6 @@ header-y += fuse.h
header-y += futex.h
header-y += gameport.h
header-y += gen_stats.h
-header-y += generic_serial.h
header-y += genetlink.h
header-y += gfs2_ondisk.h
header-y += gigaset_dev.h
@@ -372,6 +369,7 @@ header-y += tipc.h
header-y += tipc_config.h
header-y += toshiba.h
header-y += tty.h
+header-y += tty_flags.h
header-y += types.h
header-y += udf_fs_i.h
header-y += udp.h
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h
index d117b29d1062..f612c783170f 100644
--- a/include/linux/amba/serial.h
+++ b/include/linux/amba/serial.h
@@ -205,7 +205,6 @@ struct amba_pl011_data {
void *dma_tx_param;
void (*init) (void);
void (*exit) (void);
- void (*reset) (void);
};
#endif
diff --git a/include/linux/cd1400.h b/include/linux/cd1400.h
deleted file mode 100644
index 1dc3ab0523fd..000000000000
--- a/include/linux/cd1400.h
+++ /dev/null
@@ -1,292 +0,0 @@
-/*****************************************************************************/
-
-/*
- * cd1400.h -- cd1400 UART hardware info.
- *
- * Copyright (C) 1996-1998 Stallion Technologies
- * Copyright (C) 1994-1996 Greg Ungerer.
- *
- * 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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*****************************************************************************/
-#ifndef _CD1400_H
-#define _CD1400_H
-/*****************************************************************************/
-
-/*
- * Define the number of async ports per cd1400 uart chip.
- */
-#define CD1400_PORTS 4
-
-/*
- * Define the cd1400 uarts internal FIFO sizes.
- */
-#define CD1400_TXFIFOSIZE 12
-#define CD1400_RXFIFOSIZE 12
-
-/*
- * Local RX FIFO thresh hold level. Also define the RTS thresh hold
- * based on the RX thresh hold.
- */
-#define FIFO_RXTHRESHOLD 6
-#define FIFO_RTSTHRESHOLD 7
-
-/*****************************************************************************/
-
-/*
- * Define the cd1400 register addresses. These are all the valid
- * registers with the cd1400. Some are global, some virtual, some
- * per port.
- */
-#define GFRCR 0x40
-#define CAR 0x68
-#define GCR 0x4b
-#define SVRR 0x67
-#define RICR 0x44
-#define TICR 0x45
-#define MICR 0x46
-#define RIR 0x6b
-#define TIR 0x6a
-#define MIR 0x69
-#define PPR 0x7e
-
-#define RIVR 0x43
-#define TIVR 0x42
-#define MIVR 0x41
-#define TDR 0x63
-#define RDSR 0x62
-#define MISR 0x4c
-#define EOSRR 0x60
-
-#define LIVR 0x18
-#define CCR 0x05
-#define SRER 0x06
-#define COR1 0x08
-#define COR2 0x09
-#define COR3 0x0a
-#define COR4 0x1e
-#define COR5 0x1f
-#define CCSR 0x0b
-#define RDCR 0x0e
-#define SCHR1 0x1a
-#define SCHR2 0x1b
-#define SCHR3 0x1c
-#define SCHR4 0x1d
-#define SCRL 0x22
-#define SCRH 0x23
-#define LNC 0x24
-#define MCOR1 0x15
-#define MCOR2 0x16
-#define RTPR 0x21
-#define MSVR1 0x6c
-#define MSVR2 0x6d
-#define PSVR 0x6f
-#define RBPR 0x78
-#define RCOR 0x7c
-#define TBPR 0x72
-#define TCOR 0x76
-
-/*****************************************************************************/
-
-/*
- * Define the set of baud rate clock divisors.
- */
-#define CD1400_CLK0 8
-#define CD1400_CLK1 32
-#define CD1400_CLK2 128
-#define CD1400_CLK3 512
-#define CD1400_CLK4 2048
-
-#define CD1400_NUMCLKS 5
-
-/*****************************************************************************/
-
-/*
- * Define the clock pre-scalar value to be a 5 ms clock. This should be
- * OK for now. It would probably be better to make it 10 ms, but we
- * can't fit that divisor into 8 bits!
- */
-#define PPR_SCALAR 244
-
-/*****************************************************************************/
-
-/*
- * Define values used to set character size options.
- */
-#define COR1_CHL5 0x00
-#define COR1_CHL6 0x01
-#define COR1_CHL7 0x02
-#define COR1_CHL8 0x03
-
-/*
- * Define values used to set the number of stop bits.
- */
-#define COR1_STOP1 0x00
-#define COR1_STOP15 0x04
-#define COR1_STOP2 0x08
-
-/*
- * Define values used to set the parity scheme in use.
- */
-#define COR1_PARNONE 0x00
-#define COR1_PARFORCE 0x20
-#define COR1_PARENB 0x40
-#define COR1_PARIGNORE 0x10
-
-#define COR1_PARODD 0x80
-#define COR1_PAREVEN 0x00
-
-#define COR2_IXM 0x80
-#define COR2_TXIBE 0x40
-#define COR2_ETC 0x20
-#define COR2_LLM 0x10
-#define COR2_RLM 0x08
-#define COR2_RTSAO 0x04
-#define COR2_CTSAE 0x02
-
-#define COR3_SCDRNG 0x80
-#define COR3_SCD34 0x40
-#define COR3_FCT 0x20
-#define COR3_SCD12 0x10
-
-/*
- * Define values used by COR4.
- */
-#define COR4_BRKINT 0x08
-#define COR4_IGNBRK 0x18
-
-/*****************************************************************************/
-
-/*
- * Define the modem control register values.
- * Note that the actual hardware is a little different to the conventional
- * pin names on the cd1400.
- */
-#define MSVR1_DTR 0x01
-#define MSVR1_DSR 0x10
-#define MSVR1_RI 0x20
-#define MSVR1_CTS 0x40
-#define MSVR1_DCD 0x80
-
-#define MSVR2_RTS 0x02
-#define MSVR2_DSR 0x10
-#define MSVR2_RI 0x20
-#define MSVR2_CTS 0x40
-#define MSVR2_DCD 0x80
-
-#define MCOR1_DCD 0x80
-#define MCOR1_CTS 0x40
-#define MCOR1_RI 0x20
-#define MCOR1_DSR 0x10
-
-#define MCOR2_DCD 0x80
-#define MCOR2_CTS 0x40
-#define MCOR2_RI 0x20
-#define MCOR2_DSR 0x10
-
-/*****************************************************************************/
-
-/*
- * Define the bits used with the service (interrupt) enable register.
- */
-#define SRER_NNDT 0x01
-#define SRER_TXEMPTY 0x02
-#define SRER_TXDATA 0x04
-#define SRER_RXDATA 0x10
-#define SRER_MODEM 0x80
-
-/*****************************************************************************/
-
-/*
- * Define operational commands for the command register.
- */
-#define CCR_RESET 0x80
-#define CCR_CORCHANGE 0x4e
-#define CCR_SENDCH 0x20
-#define CCR_CHANCTRL 0x10
-
-#define CCR_TXENABLE (CCR_CHANCTRL | 0x08)
-#define CCR_TXDISABLE (CCR_CHANCTRL | 0x04)
-#define CCR_RXENABLE (CCR_CHANCTRL | 0x02)
-#define CCR_RXDISABLE (CCR_CHANCTRL | 0x01)
-
-#define CCR_SENDSCHR1 (CCR_SENDCH | 0x01)
-#define CCR_SENDSCHR2 (CCR_SENDCH | 0x02)
-#define CCR_SENDSCHR3 (CCR_SENDCH | 0x03)
-#define CCR_SENDSCHR4 (CCR_SENDCH | 0x04)
-
-#define CCR_RESETCHAN (CCR_RESET | 0x00)
-#define CCR_RESETFULL (CCR_RESET | 0x01)
-#define CCR_TXFLUSHFIFO (CCR_RESET | 0x02)
-
-#define CCR_MAXWAIT 10000
-
-/*****************************************************************************/
-
-/*
- * Define the valid acknowledgement types (for hw ack cycle).
- */
-#define ACK_TYPMASK 0x07
-#define ACK_TYPTX 0x02
-#define ACK_TYPMDM 0x01
-#define ACK_TYPRXGOOD 0x03
-#define ACK_TYPRXBAD 0x07
-
-#define SVRR_RX 0x01
-#define SVRR_TX 0x02
-#define SVRR_MDM 0x04
-
-#define ST_OVERRUN 0x01
-#define ST_FRAMING 0x02
-#define ST_PARITY 0x04
-#define ST_BREAK 0x08
-#define ST_SCHAR1 0x10
-#define ST_SCHAR2 0x20
-#define ST_SCHAR3 0x30
-#define ST_SCHAR4 0x40
-#define ST_RANGE 0x70
-#define ST_SCHARMASK 0x70
-#define ST_TIMEOUT 0x80
-
-#define MISR_DCD 0x80
-#define MISR_CTS 0x40
-#define MISR_RI 0x20
-#define MISR_DSR 0x10
-
-/*****************************************************************************/
-
-/*
- * Defines for the CCSR status register.
- */
-#define CCSR_RXENABLED 0x80
-#define CCSR_RXFLOWON 0x40
-#define CCSR_RXFLOWOFF 0x20
-#define CCSR_TXENABLED 0x08
-#define CCSR_TXFLOWON 0x04
-#define CCSR_TXFLOWOFF 0x02
-
-/*****************************************************************************/
-
-/*
- * Define the embedded commands.
- */
-#define ETC_CMD 0x00
-#define ETC_STARTBREAK 0x81
-#define ETC_DELAY 0x82
-#define ETC_STOPBREAK 0x83
-
-/*****************************************************************************/
-#endif
diff --git a/include/linux/cdk.h b/include/linux/cdk.h
deleted file mode 100644
index 80093a8d4f64..000000000000
--- a/include/linux/cdk.h
+++ /dev/null
@@ -1,486 +0,0 @@
-/*****************************************************************************/
-
-/*
- * cdk.h -- CDK interface definitions.
- *
- * Copyright (C) 1996-1998 Stallion Technologies
- * Copyright (C) 1994-1996 Greg Ungerer.
- *
- * 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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*****************************************************************************/
-#ifndef _CDK_H
-#define _CDK_H
-/*****************************************************************************/
-
-#pragma pack(2)
-
-/*
- * The following set of definitions is used to communicate with the
- * shared memory interface of the Stallion intelligent multiport serial
- * boards. The definitions in this file are taken directly from the
- * document titled "Generic Stackable Interface, Downloader and
- * Communications Development Kit".
- */
-
-/*
- * Define the set of important shared memory addresses. These are
- * required to initialize the board and get things started. All of these
- * addresses are relative to the start of the shared memory.
- */
-#define CDK_SIGADDR 0x200
-#define CDK_FEATADDR 0x280
-#define CDK_CDKADDR 0x300
-#define CDK_RDYADDR 0x262
-
-#define CDK_ALIVEMARKER 13
-
-/*
- * On hardware power up the ROMs located on the EasyConnection 8/64 will
- * fill out the following signature information into shared memory. This
- * way the host system can quickly determine that the board is present
- * and is operational.
- */
-typedef struct cdkecpsig {
- unsigned long magic;
- unsigned short romver;
- unsigned short cputype;
- unsigned char panelid[8];
-} cdkecpsig_t;
-
-#define ECP_MAGIC 0x21504345
-
-/*
- * On hardware power up the ROMs located on the ONboard, Stallion and
- * Brumbys will fill out the following signature information into shared
- * memory. This way the host system can quickly determine that the board
- * is present and is operational.
- */
-typedef struct cdkonbsig {
- unsigned short magic0;
- unsigned short magic1;
- unsigned short magic2;
- unsigned short magic3;
- unsigned short romver;
- unsigned short memoff;
- unsigned short memseg;
- unsigned short amask0;
- unsigned short pic;
- unsigned short status;
- unsigned short btype;
- unsigned short clkticks;
- unsigned short clkspeed;
- unsigned short amask1;
- unsigned short amask2;
-} cdkonbsig_t;
-
-#define ONB_MAGIC0 0xf2a7
-#define ONB_MAGIC1 0xa149
-#define ONB_MAGIC2 0x6352
-#define ONB_MAGIC3 0xf121
-
-/*
- * Define the feature area structure. The feature area is the set of
- * startup parameters used by the slave image when it starts executing.
- * They allow for the specification of buffer sizes, debug trace, etc.
- */
-typedef struct cdkfeature {
- unsigned long debug;
- unsigned long banner;
- unsigned long etype;
- unsigned long nrdevs;
- unsigned long brdspec;
- unsigned long txrqsize;
- unsigned long rxrqsize;
- unsigned long flags;
-} cdkfeature_t;
-
-#define ETYP_DDK 0
-#define ETYP_CDK 1
-
-/*
- * Define the CDK header structure. This is the info that the slave
- * environment sets up after it has been downloaded and started. It
- * essentially provides a memory map for the shared memory interface.
- */
-typedef struct cdkhdr {
- unsigned short command;
- unsigned short status;
- unsigned short port;
- unsigned short mode;
- unsigned long cmd_buf[14];
- unsigned short alive_cnt;
- unsigned short intrpt_mode;
- unsigned char intrpt_id[8];
- unsigned char ver_release;
- unsigned char ver_modification;
- unsigned char ver_fix;
- unsigned char deadman_restart;
- unsigned short deadman;
- unsigned short nrdevs;
- unsigned long memp;
- unsigned long hostp;
- unsigned long slavep;
- unsigned char hostreq;
- unsigned char slavereq;
- unsigned char cmd_reserved[30];
-} cdkhdr_t;
-
-#define MODE_DDK 0
-#define MODE_CDK 1
-
-#define IMD_INTR 0x0
-#define IMD_PPINTR 0x1
-#define IMD_POLL 0xff
-
-/*
- * Define the memory mapping structure. This structure is pointed to by
- * the memp field in the stlcdkhdr struct. As many as these structures
- * as required are laid out in shared memory to define how the rest of
- * shared memory is divided up. There will be one for each port.
- */
-typedef struct cdkmem {
- unsigned short dtype;
- unsigned long offset;
-} cdkmem_t;
-
-#define TYP_UNDEFINED 0x0
-#define TYP_ASYNCTRL 0x1
-#define TYP_ASYNC 0x20
-#define TYP_PARALLEL 0x40
-#define TYP_SYNCX21 0x60
-
-/*****************************************************************************/
-
-/*
- * Following is a set of defines and structures used to actually deal
- * with the serial ports on the board. Firstly is the set of commands
- * that can be applied to ports.
- */
-#define ASYCMD (((unsigned long) 'a') << 8)
-
-#define A_NULL (ASYCMD | 0)
-#define A_FLUSH (ASYCMD | 1)
-#define A_BREAK (ASYCMD | 2)
-#define A_GETPORT (ASYCMD | 3)
-#define A_SETPORT (ASYCMD | 4)
-#define A_SETPORTF (ASYCMD | 5)
-#define A_SETPORTFTX (ASYCMD | 6)
-#define A_SETPORTFRX (ASYCMD | 7)
-#define A_GETSIGNALS (ASYCMD | 8)
-#define A_SETSIGNALS (ASYCMD | 9)
-#define A_SETSIGNALSF (ASYCMD | 10)
-#define A_SETSIGNALSFTX (ASYCMD | 11)
-#define A_SETSIGNALSFRX (ASYCMD | 12)
-#define A_GETNOTIFY (ASYCMD | 13)
-#define A_SETNOTIFY (ASYCMD | 14)
-#define A_NOTIFY (ASYCMD | 15)
-#define A_PORTCTRL (ASYCMD | 16)
-#define A_GETSTATS (ASYCMD | 17)
-#define A_RQSTATE (ASYCMD | 18)
-#define A_FLOWSTATE (ASYCMD | 19)
-#define A_CLEARSTATS (ASYCMD | 20)
-
-/*
- * Define those arguments used for simple commands.
- */
-#define FLUSHRX 0x1
-#define FLUSHTX 0x2
-
-#define BREAKON -1
-#define BREAKOFF -2
-
-/*
- * Define the port setting structure, and all those defines that go along
- * with it. Basically this structure defines the characteristics of this
- * port: baud rate, chars, parity, input/output char cooking etc.
- */
-typedef struct asyport {
- unsigned long baudout;
- unsigned long baudin;
- unsigned long iflag;
- unsigned long oflag;
- unsigned long lflag;
- unsigned long pflag;
- unsigned long flow;
- unsigned long spare1;
- unsigned short vtime;
- unsigned short vmin;
- unsigned short txlo;
- unsigned short txhi;
- unsigned short rxlo;
- unsigned short rxhi;
- unsigned short rxhog;
- unsigned short spare2;
- unsigned char csize;
- unsigned char stopbs;
- unsigned char parity;
- unsigned char stopin;
- unsigned char startin;
- unsigned char stopout;
- unsigned char startout;
- unsigned char parmark;
- unsigned char brkmark;
- unsigned char cc[11];
-} asyport_t;
-
-#define PT_STOP1 0x0
-#define PT_STOP15 0x1
-#define PT_STOP2 0x2
-
-#define PT_NOPARITY 0x0
-#define PT_ODDPARITY 0x1
-#define PT_EVENPARITY 0x2
-#define PT_MARKPARITY 0x3
-#define PT_SPACEPARITY 0x4
-
-#define F_NONE 0x0
-#define F_IXON 0x1
-#define F_IXOFF 0x2
-#define F_IXANY 0x4
-#define F_IOXANY 0x8
-#define F_RTSFLOW 0x10
-#define F_CTSFLOW 0x20
-#define F_DTRFLOW 0x40
-#define F_DCDFLOW 0x80
-#define F_DSROFLOW 0x100
-#define F_DSRIFLOW 0x200
-
-#define FI_NORX 0x1
-#define FI_RAW 0x2
-#define FI_ISTRIP 0x4
-#define FI_UCLC 0x8
-#define FI_INLCR 0x10
-#define FI_ICRNL 0x20
-#define FI_IGNCR 0x40
-#define FI_IGNBREAK 0x80
-#define FI_DSCRDBREAK 0x100
-#define FI_1MARKBREAK 0x200
-#define FI_2MARKBREAK 0x400
-#define FI_XCHNGBREAK 0x800
-#define FI_IGNRXERRS 0x1000
-#define FI_DSCDRXERRS 0x2000
-#define FI_1MARKRXERRS 0x4000
-#define FI_2MARKRXERRS 0x8000
-#define FI_XCHNGRXERRS 0x10000
-#define FI_DSCRDNULL 0x20000
-
-#define FO_OLCUC 0x1
-#define FO_ONLCR 0x2
-#define FO_OOCRNL 0x4
-#define FO_ONOCR 0x8
-#define FO_ONLRET 0x10
-#define FO_ONL 0x20
-#define FO_OBS 0x40
-#define FO_OVT 0x80
-#define FO_OFF 0x100
-#define FO_OTAB1 0x200
-#define FO_OTAB2 0x400
-#define FO_OTAB3 0x800
-#define FO_OCR1 0x1000
-#define FO_OCR2 0x2000
-#define FO_OCR3 0x4000
-#define FO_OFILL 0x8000
-#define FO_ODELL 0x10000
-
-#define P_RTSLOCK 0x1
-#define P_CTSLOCK 0x2
-#define P_MAPRTS 0x4
-#define P_MAPCTS 0x8
-#define P_LOOPBACK 0x10
-#define P_DTRFOLLOW 0x20
-#define P_FAKEDCD 0x40
-
-#define P_RXIMIN 0x10000
-#define P_RXITIME 0x20000
-#define P_RXTHOLD 0x40000
-
-/*
- * Define a structure to communicate serial port signal and data state
- * information.
- */
-typedef struct asysigs {
- unsigned long data;
- unsigned long signal;
- unsigned long sigvalue;
-} asysigs_t;
-
-#define DT_TXBUSY 0x1
-#define DT_TXEMPTY 0x2
-#define DT_TXLOW 0x4
-#define DT_TXHIGH 0x8
-#define DT_TXFULL 0x10
-#define DT_TXHOG 0x20
-#define DT_TXFLOWED 0x40
-#define DT_TXBREAK 0x80
-
-#define DT_RXBUSY 0x100
-#define DT_RXEMPTY 0x200
-#define DT_RXLOW 0x400
-#define DT_RXHIGH 0x800
-#define DT_RXFULL 0x1000
-#define DT_RXHOG 0x2000
-#define DT_RXFLOWED 0x4000
-#define DT_RXBREAK 0x8000
-
-#define SG_DTR 0x1
-#define SG_DCD 0x2
-#define SG_RTS 0x4
-#define SG_CTS 0x8
-#define SG_DSR 0x10
-#define SG_RI 0x20
-
-/*
- * Define the notification setting structure. This is used to tell the
- * port what events we want to be informed about. Fields here use the
- * same defines as for the asysigs structure above.
- */
-typedef struct asynotify {
- unsigned long ctrl;
- unsigned long data;
- unsigned long signal;
- unsigned long sigvalue;
-} asynotify_t;
-
-/*
- * Define the port control structure. It is used to do fine grain
- * control operations on the port.
- */
-typedef struct {
- unsigned long rxctrl;
- unsigned long txctrl;
- char rximdch;
- char tximdch;
- char spare1;
- char spare2;
-} asyctrl_t;
-
-#define CT_ENABLE 0x1
-#define CT_DISABLE 0x2
-#define CT_STOP 0x4
-#define CT_START 0x8
-#define CT_STARTFLOW 0x10
-#define CT_STOPFLOW 0x20
-#define CT_SENDCHR 0x40
-
-/*
- * Define the stats structure kept for each port. This is a useful set
- * of data collected for each port on the slave. The A_GETSTATS command
- * is used to retrieve this data from the slave.
- */
-typedef struct asystats {
- unsigned long opens;
- unsigned long txchars;
- unsigned long rxchars;
- unsigned long txringq;
- unsigned long rxringq;
- unsigned long txmsgs;
- unsigned long rxmsgs;
- unsigned long txflushes;
- unsigned long rxflushes;
- unsigned long overruns;
- unsigned long framing;
- unsigned long parity;
- unsigned long ringover;
- unsigned long lost;
- unsigned long rxstart;
- unsigned long rxstop;
- unsigned long txstart;
- unsigned long txstop;
- unsigned long dcdcnt;
- unsigned long dtrcnt;
- unsigned long ctscnt;
- unsigned long rtscnt;
- unsigned long dsrcnt;
- unsigned long ricnt;
- unsigned long txbreaks;
- unsigned long rxbreaks;
- unsigned long signals;
- unsigned long state;
- unsigned long hwid;
-} asystats_t;
-
-/*****************************************************************************/
-
-/*
- * All command and control communication with a device on the slave is
- * via a control block in shared memory. Each device has its own control
- * block, defined by the following structure. The control block allows
- * the host to open, close and control the device on the slave.
- */
-typedef struct cdkctrl {
- unsigned char open;
- unsigned char close;
- unsigned long openarg;
- unsigned long closearg;
- unsigned long cmd;
- unsigned long status;
- unsigned long args[32];
-} cdkctrl_t;
-
-/*
- * Each device on the slave passes data to and from the host via a ring
- * queue in shared memory. Define a ring queue structure to hold the
- * vital information about each ring queue. Two ring queues will be
- * allocated for each port, one for receive data and one for transmit
- * data.
- */
-typedef struct cdkasyrq {
- unsigned long offset;
- unsigned short size;
- unsigned short head;
- unsigned short tail;
-} cdkasyrq_t;
-
-/*
- * Each asynchronous port is defined in shared memory by the following
- * structure. It contains a control block to command a device, and also
- * the necessary data channel information as well.
- */
-typedef struct cdkasy {
- cdkctrl_t ctrl;
- unsigned short notify;
- asynotify_t changed;
- unsigned short receive;
- cdkasyrq_t rxq;
- unsigned short transmit;
- cdkasyrq_t txq;
-} cdkasy_t;
-
-#pragma pack()
-
-/*****************************************************************************/
-
-/*
- * Define the set of ioctls used by the driver to do special things
- * to the board. These include interrupting it, and initializing
- * the driver after board startup and shutdown.
- */
-#include <linux/ioctl.h>
-
-#define STL_BINTR _IO('s',20)
-#define STL_BSTART _IO('s',21)
-#define STL_BSTOP _IO('s',22)
-#define STL_BRESET _IO('s',23)
-
-/*
- * Define a set of ioctl extensions, used to get at special stuff.
- */
-#define STL_GETPFLAG _IO('s',80)
-#define STL_SETPFLAG _IO('s',81)
-
-/*****************************************************************************/
-#endif
diff --git a/include/linux/comstats.h b/include/linux/comstats.h
deleted file mode 100644
index 3f5ea8e8026d..000000000000
--- a/include/linux/comstats.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*****************************************************************************/
-
-/*
- * comstats.h -- Serial Port Stats.
- *
- * Copyright (C) 1996-1998 Stallion Technologies
- * Copyright (C) 1994-1996 Greg Ungerer.
- *
- * 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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*****************************************************************************/
-#ifndef _COMSTATS_H
-#define _COMSTATS_H
-/*****************************************************************************/
-
-/*
- * Serial port stats structure. The structure itself is UART
- * independent, but some fields may be UART/driver specific (for
- * example state).
- */
-
-typedef struct {
- unsigned long brd;
- unsigned long panel;
- unsigned long port;
- unsigned long hwid;
- unsigned long type;
- unsigned long txtotal;
- unsigned long rxtotal;
- unsigned long txbuffered;
- unsigned long rxbuffered;
- unsigned long rxoverrun;
- unsigned long rxparity;
- unsigned long rxframing;
- unsigned long rxlost;
- unsigned long txbreaks;
- unsigned long rxbreaks;
- unsigned long txxon;
- unsigned long txxoff;
- unsigned long rxxon;
- unsigned long rxxoff;
- unsigned long txctson;
- unsigned long txctsoff;
- unsigned long rxrtson;
- unsigned long rxrtsoff;
- unsigned long modem;
- unsigned long state;
- unsigned long flags;
- unsigned long ttystate;
- unsigned long cflags;
- unsigned long iflags;
- unsigned long oflags;
- unsigned long lflags;
- unsigned long signals;
-} comstats_t;
-
-
-/*
- * Board stats structure. Returns useful info about the board.
- */
-
-#define COM_MAXPANELS 8
-
-typedef struct {
- unsigned long panel;
- unsigned long type;
- unsigned long hwid;
- unsigned long nrports;
-} companel_t;
-
-typedef struct {
- unsigned long brd;
- unsigned long type;
- unsigned long hwid;
- unsigned long state;
- unsigned long ioaddr;
- unsigned long ioaddr2;
- unsigned long memaddr;
- unsigned long irq;
- unsigned long nrpanels;
- unsigned long nrports;
- companel_t panels[COM_MAXPANELS];
-} combrd_t;
-
-
-/*
- * Define the ioctl operations for stats stuff.
- */
-#include <linux/ioctl.h>
-
-#define COM_GETPORTSTATS _IO('c',30)
-#define COM_CLRPORTSTATS _IO('c',31)
-#define COM_GETBRDSTATS _IO('c',32)
-
-
-/*
- * Define the set of ioctls that give user level access to the
- * private port, panel and board structures. The argument required
- * will be driver dependent!
- */
-#define COM_READPORT _IO('c',40)
-#define COM_READBOARD _IO('c',41)
-#define COM_READPANEL _IO('c',42)
-
-/*****************************************************************************/
-#endif
diff --git a/include/linux/generic_serial.h b/include/linux/generic_serial.h
deleted file mode 100644
index 79b3eb37243a..000000000000
--- a/include/linux/generic_serial.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * generic_serial.h
- *
- * Copyright (C) 1998 R.E.Wolff@BitWizard.nl
- *
- * written for the SX serial driver.
- *
- * Version 0.1 -- December, 1998.
- */
-
-#ifndef GENERIC_SERIAL_H
-#define GENERIC_SERIAL_H
-
-#warning Use of this header is deprecated.
-#warning Since nobody sets the constants defined here for you, you should not, in any case, use them. Including the header is thus pointless.
-
-/* Flags */
-/* Warning: serial.h defines some ASYNC_ flags, they say they are "only"
- used in serial.c, but they are also used in all other serial drivers.
- Make sure they don't clash with these here... */
-#define GS_TX_INTEN 0x00800000
-#define GS_RX_INTEN 0x00400000
-#define GS_ACTIVE 0x00200000
-
-#define GS_TYPE_NORMAL 1
-
-#define GS_DEBUG_FLUSH 0x00000001
-#define GS_DEBUG_BTR 0x00000002
-#define GS_DEBUG_TERMIOS 0x00000004
-#define GS_DEBUG_STUFF 0x00000008
-#define GS_DEBUG_CLOSE 0x00000010
-#define GS_DEBUG_FLOW 0x00000020
-#define GS_DEBUG_WRITE 0x00000040
-
-#endif
diff --git a/include/linux/istallion.h b/include/linux/istallion.h
deleted file mode 100644
index ad700a60c158..000000000000
--- a/include/linux/istallion.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*****************************************************************************/
-
-/*
- * istallion.h -- stallion intelligent multiport serial driver.
- *
- * Copyright (C) 1996-1998 Stallion Technologies
- * Copyright (C) 1994-1996 Greg Ungerer.
- *
- * 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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*****************************************************************************/
-#ifndef _ISTALLION_H
-#define _ISTALLION_H
-/*****************************************************************************/
-
-/*
- * Define important driver constants here.
- */
-#define STL_MAXBRDS 4
-#define STL_MAXPANELS 4
-#define STL_MAXPORTS 64
-#define STL_MAXCHANS (STL_MAXPORTS + 1)
-#define STL_MAXDEVS (STL_MAXBRDS * STL_MAXPORTS)
-
-
-/*
- * Define a set of structures to hold all the board/panel/port info
- * for our ports. These will be dynamically allocated as required at
- * driver initialization time.
- */
-
-/*
- * Port and board structures to hold status info about each object.
- * The board structure contains pointers to structures for each port
- * connected to it. Panels are not distinguished here, since
- * communication with the slave board will always be on a per port
- * basis.
- */
-struct stliport {
- unsigned long magic;
- struct tty_port port;
- unsigned int portnr;
- unsigned int panelnr;
- unsigned int brdnr;
- unsigned long state;
- unsigned int devnr;
- int baud_base;
- int custom_divisor;
- int closing_wait;
- int rc;
- int argsize;
- void *argp;
- unsigned int rxmarkmsk;
- wait_queue_head_t raw_wait;
- struct asysigs asig;
- unsigned long addr;
- unsigned long rxoffset;
- unsigned long txoffset;
- unsigned long sigs;
- unsigned long pflag;
- unsigned int rxsize;
- unsigned int txsize;
- unsigned char reqbit;
- unsigned char portidx;
- unsigned char portbit;
-};
-
-/*
- * Use a structure of function pointers to do board level operations.
- * These include, enable/disable, paging shared memory, interrupting, etc.
- */
-struct stlibrd {
- unsigned long magic;
- unsigned int brdnr;
- unsigned int brdtype;
- unsigned long state;
- unsigned int nrpanels;
- unsigned int nrports;
- unsigned int nrdevs;
- unsigned int iobase;
- int iosize;
- unsigned long memaddr;
- void __iomem *membase;
- unsigned long memsize;
- int pagesize;
- int hostoffset;
- int slaveoffset;
- int bitsize;
- int enabval;
- unsigned int panels[STL_MAXPANELS];
- int panelids[STL_MAXPANELS];
- void (*init)(struct stlibrd *brdp);
- void (*enable)(struct stlibrd *brdp);
- void (*reenable)(struct stlibrd *brdp);
- void (*disable)(struct stlibrd *brdp);
- void __iomem *(*getmemptr)(struct stlibrd *brdp, unsigned long offset, int line);
- void (*intr)(struct stlibrd *brdp);
- void (*reset)(struct stlibrd *brdp);
- struct stliport *ports[STL_MAXPORTS];
-};
-
-
-/*
- * Define MAGIC numbers used for above structures.
- */
-#define STLI_PORTMAGIC 0xe671c7a1
-#define STLI_BOARDMAGIC 0x4bc6c825
-
-/*****************************************************************************/
-#endif
diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h
index daf4a3a40ee0..b7c8cdc1d422 100644
--- a/include/linux/kbd_kern.h
+++ b/include/linux/kbd_kern.h
@@ -65,7 +65,6 @@ struct kbd_struct {
extern int kbd_init(void);
-extern unsigned char getledstate(void);
extern void setledstate(struct kbd_struct *kbd, unsigned int led);
extern int do_poke_blanked_console;
@@ -145,16 +144,4 @@ void compute_shiftstate(void);
extern unsigned int keymap_count;
-/* console.c */
-
-static inline void con_schedule_flip(struct tty_struct *t)
-{
- unsigned long flags;
- spin_lock_irqsave(&t->buf.lock, flags);
- if (t->buf.tail != NULL)
- t->buf.tail->commit = t->buf.tail->used;
- spin_unlock_irqrestore(&t->buf.lock, flags);
- schedule_work(&t->buf.work);
-}
-
#endif
diff --git a/include/linux/kdb.h b/include/linux/kdb.h
index 42d9e863a313..7f6fe6e015bc 100644
--- a/include/linux/kdb.h
+++ b/include/linux/kdb.h
@@ -13,6 +13,14 @@
* Copyright (C) 2009 Jason Wessel <jason.wessel@windriver.com>
*/
+typedef enum {
+ KDB_REPEAT_NONE = 0, /* Do not repeat this command */
+ KDB_REPEAT_NO_ARGS, /* Repeat the command without arguments */
+ KDB_REPEAT_WITH_ARGS, /* Repeat the command including its arguments */
+} kdb_repeat_t;
+
+typedef int (*kdb_func_t)(int, const char **);
+
#ifdef CONFIG_KGDB_KDB
#include <linux/init.h>
#include <linux/sched.h>
@@ -32,14 +40,6 @@ extern atomic_t kdb_event;
#define KDB_MAXARGS 16 /* Maximum number of arguments to a function */
-typedef enum {
- KDB_REPEAT_NONE = 0, /* Do not repeat this command */
- KDB_REPEAT_NO_ARGS, /* Repeat the command without arguments */
- KDB_REPEAT_WITH_ARGS, /* Repeat the command including its arguments */
-} kdb_repeat_t;
-
-typedef int (*kdb_func_t)(int, const char **);
-
/* KDB return codes from a command or internal kdb function */
#define KDB_NOTFOUND (-1)
#define KDB_ARGCOUNT (-2)
@@ -149,11 +149,14 @@ extern int kdb_register_repeat(char *, kdb_func_t, char *, char *,
short, kdb_repeat_t);
extern int kdb_unregister(char *);
#else /* ! CONFIG_KGDB_KDB */
-#define kdb_printf(...)
-#define kdb_init(x)
-#define kdb_register(...)
-#define kdb_register_repeat(...)
-#define kdb_uregister(x)
+static inline __printf(1, 2) int kdb_printf(const char *fmt, ...) { return 0; }
+static inline void kdb_init(int level) {}
+static inline int kdb_register(char *cmd, kdb_func_t func, char *usage,
+ char *help, short minlen) { return 0; }
+static inline int kdb_register_repeat(char *cmd, kdb_func_t func, char *usage,
+ char *help, short minlen,
+ kdb_repeat_t repeat) { return 0; }
+static inline int kdb_unregister(char *cmd) { return 0; }
#endif /* CONFIG_KGDB_KDB */
enum {
KDB_NOT_INITIALIZED,
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h
index c4d2fc194ede..4dff0c6ed58f 100644
--- a/include/linux/kgdb.h
+++ b/include/linux/kgdb.h
@@ -240,6 +240,7 @@ extern void kgdb_arch_late(void);
* hardware breakpoints.
* @correct_hw_break: Allow an architecture to specify how to correct the
* hardware debug registers.
+ * @enable_nmi: Manage NMI-triggered entry to KGDB
*/
struct kgdb_arch {
unsigned char gdb_bpt_instr[BREAK_INSTR_SIZE];
@@ -252,6 +253,8 @@ struct kgdb_arch {
void (*disable_hw_break)(struct pt_regs *regs);
void (*remove_all_hw_break)(void);
void (*correct_hw_break)(void);
+
+ void (*enable_nmi)(bool on);
};
/**
@@ -283,6 +286,16 @@ extern struct kgdb_arch arch_kgdb_ops;
extern unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs);
+#ifdef CONFIG_SERIAL_KGDB_NMI
+extern int kgdb_register_nmi_console(void);
+extern int kgdb_unregister_nmi_console(void);
+extern bool kgdb_nmi_poll_knock(void);
+#else
+static inline int kgdb_register_nmi_console(void) { return 0; }
+static inline int kgdb_unregister_nmi_console(void) { return 0; }
+static inline bool kgdb_nmi_poll_knock(void) { return 1; }
+#endif
+
extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops);
extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops);
extern struct kgdb_io *dbg_io_ops;
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 6b4565c440c8..8d3c42719387 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1847,7 +1847,6 @@
#define PCI_DEVICE_ID_SIIG_8S_20x_650 0x2081
#define PCI_DEVICE_ID_SIIG_8S_20x_850 0x2082
#define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL 0x2050
-#define PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL 0x2530
#define PCI_VENDOR_ID_RADISYS 0x1331
diff --git a/include/linux/platform_data/max310x.h b/include/linux/platform_data/max310x.h
new file mode 100644
index 000000000000..91648bf5fc5c
--- /dev/null
+++ b/include/linux/platform_data/max310x.h
@@ -0,0 +1,67 @@
+/*
+ * Maxim (Dallas) MAX3107/8 serial driver
+ *
+ * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * Based on max3100.c, by Christian Pellegrin <chripell@evolware.org>
+ * Based on max3110.c, by Feng Tang <feng.tang@intel.com>
+ * Based on max3107.c, by Aavamobile
+ *
+ * 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.
+ */
+
+#ifndef _MAX310X_H_
+#define _MAX310X_H_
+
+/*
+ * Example board initialization data:
+ *
+ * static struct max310x_pdata max3107_pdata = {
+ * .driver_flags = MAX310X_EXT_CLK,
+ * .uart_flags[0] = MAX310X_ECHO_SUPRESS | MAX310X_AUTO_DIR_CTRL,
+ * .frequency = 3686400,
+ * .gpio_base = -1,
+ * };
+ *
+ * static struct spi_board_info spi_device_max3107[] = {
+ * {
+ * .modalias = "max3107",
+ * .irq = IRQ_EINT3,
+ * .bus_num = 1,
+ * .chip_select = 1,
+ * .platform_data = &max3107_pdata,
+ * },
+ * };
+ */
+
+#define MAX310X_MAX_UARTS 1
+
+/* MAX310X platform data structure */
+struct max310x_pdata {
+ /* Flags global to driver */
+ const u8 driver_flags:2;
+#define MAX310X_EXT_CLK (0x00000001) /* External clock enable */
+#define MAX310X_AUTOSLEEP (0x00000002) /* Enable AutoSleep mode */
+ /* Flags global to UART port */
+ const u8 uart_flags[MAX310X_MAX_UARTS];
+#define MAX310X_LOOPBACK (0x00000001) /* Loopback mode enable */
+#define MAX310X_ECHO_SUPRESS (0x00000002) /* Enable echo supress */
+#define MAX310X_AUTO_DIR_CTRL (0x00000004) /* Enable Auto direction
+ * control (RS-485)
+ */
+ /* Frequency (extrenal clock or crystal) */
+ const int frequency;
+ /* GPIO base number (can be negative) */
+ const int gpio_base;
+ /* Called during startup */
+ void (*init)(void);
+ /* Called before finish */
+ void (*exit)(void);
+ /* Suspend callback */
+ void (*suspend)(int do_suspend);
+};
+
+#endif
diff --git a/include/linux/platform_data/sccnxp.h b/include/linux/platform_data/sccnxp.h
new file mode 100644
index 000000000000..7311ccd3217f
--- /dev/null
+++ b/include/linux/platform_data/sccnxp.h
@@ -0,0 +1,93 @@
+/*
+ * NXP (Philips) SCC+++(SCN+++) serial driver
+ *
+ * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * Based on sc26xx.c, by Thomas Bogendörfer (tsbogend@alpha.franken.de)
+ *
+ * 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.
+ */
+
+#ifndef __SCCNXP_H
+#define __SCCNXP_H
+
+#define SCCNXP_MAX_UARTS 2
+
+/* Output lines */
+#define LINE_OP0 1
+#define LINE_OP1 2
+#define LINE_OP2 3
+#define LINE_OP3 4
+#define LINE_OP4 5
+#define LINE_OP5 6
+#define LINE_OP6 7
+#define LINE_OP7 8
+
+/* Input lines */
+#define LINE_IP0 9
+#define LINE_IP1 10
+#define LINE_IP2 11
+#define LINE_IP3 12
+#define LINE_IP4 13
+#define LINE_IP5 14
+#define LINE_IP6 15
+
+/* Signals */
+#define DTR_OP 0 /* DTR */
+#define RTS_OP 4 /* RTS */
+#define DSR_IP 8 /* DSR */
+#define CTS_IP 12 /* CTS */
+#define DCD_IP 16 /* DCD */
+#define RNG_IP 20 /* RNG */
+
+#define DIR_OP 24 /* Special signal for control RS-485.
+ * Goes high when transmit,
+ * then goes low.
+ */
+
+/* Routing control signal 'sig' to line 'line' */
+#define MCTRL_SIG(sig, line) ((line) << (sig))
+
+/*
+ * Example board initialization data:
+ *
+ * static struct resource sc2892_resources[] = {
+ * DEFINE_RES_MEM(UART_PHYS_START, 0x10),
+ * DEFINE_RES_IRQ(IRQ_EXT2),
+ * };
+ *
+ * static struct sccnxp_pdata sc2892_info = {
+ * .frequency = 3686400,
+ * .mctrl_cfg[0] = MCTRL_SIG(DIR_OP, LINE_OP0),
+ * .mctrl_cfg[1] = MCTRL_SIG(DIR_OP, LINE_OP1),
+ * };
+ *
+ * static struct platform_device sc2892 = {
+ * .name = "sc2892",
+ * .id = -1,
+ * .resource = sc2892_resources,
+ * .num_resources = ARRAY_SIZE(sc2892_resources),
+ * .dev = {
+ * .platform_data = &sc2892_info,
+ * },
+ * };
+ */
+
+/* SCCNXP platform data structure */
+struct sccnxp_pdata {
+ /* Frequency (extrenal clock or crystal) */
+ int frequency;
+ /* Shift for A0 line */
+ const u8 reg_shift;
+ /* Modem control lines configuration */
+ const u32 mctrl_cfg[SCCNXP_MAX_UARTS];
+ /* Called during startup */
+ void (*init)(void);
+ /* Called before finish */
+ void (*exit)(void);
+};
+
+#endif
diff --git a/include/linux/sc26198.h b/include/linux/sc26198.h
deleted file mode 100644
index 7ca35abad387..000000000000
--- a/include/linux/sc26198.h
+++ /dev/null
@@ -1,533 +0,0 @@
-/*****************************************************************************/
-
-/*
- * sc26198.h -- SC26198 UART hardware info.
- *
- * Copyright (C) 1995-1998 Stallion Technologies
- *
- * 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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*****************************************************************************/
-#ifndef _SC26198_H
-#define _SC26198_H
-/*****************************************************************************/
-
-/*
- * Define the number of async ports per sc26198 uart device.
- */
-#define SC26198_PORTS 8
-
-/*
- * Baud rate timing clocks. All derived from a master 14.7456 MHz clock.
- */
-#define SC26198_MASTERCLOCK 14745600L
-#define SC26198_DCLK (SC26198_MASTERCLOCK)
-#define SC26198_CCLK (SC26198_MASTERCLOCK / 2)
-#define SC26198_BCLK (SC26198_MASTERCLOCK / 4)
-
-/*
- * Define internal FIFO sizes for the 26198 ports.
- */
-#define SC26198_TXFIFOSIZE 16
-#define SC26198_RXFIFOSIZE 16
-
-/*****************************************************************************/
-
-/*
- * Global register definitions. These registers are global to each 26198
- * device, not specific ports on it.
- */
-#define TSTR 0x0d
-#define GCCR 0x0f
-#define ICR 0x1b
-#define WDTRCR 0x1d
-#define IVR 0x1f
-#define BRGTRUA 0x84
-#define GPOSR 0x87
-#define GPOC 0x8b
-#define UCIR 0x8c
-#define CIR 0x8c
-#define BRGTRUB 0x8d
-#define GRXFIFO 0x8e
-#define GTXFIFO 0x8e
-#define GCCR2 0x8f
-#define BRGTRLA 0x94
-#define GPOR 0x97
-#define GPOD 0x9b
-#define BRGTCR 0x9c
-#define GICR 0x9c
-#define BRGTRLB 0x9d
-#define GIBCR 0x9d
-#define GITR 0x9f
-
-/*
- * Per port channel registers. These are the register offsets within
- * the port address space, so need to have the port address (0 to 7)
- * inserted in bit positions 4:6.
- */
-#define MR0 0x00
-#define MR1 0x01
-#define IOPCR 0x02
-#define BCRBRK 0x03
-#define BCRCOS 0x04
-#define BCRX 0x06
-#define BCRA 0x07
-#define XONCR 0x08
-#define XOFFCR 0x09
-#define ARCR 0x0a
-#define RXCSR 0x0c
-#define TXCSR 0x0e
-#define MR2 0x80
-#define SR 0x81
-#define SCCR 0x81
-#define ISR 0x82
-#define IMR 0x82
-#define TXFIFO 0x83
-#define RXFIFO 0x83
-#define IPR 0x84
-#define IOPIOR 0x85
-#define XISR 0x86
-
-/*
- * For any given port calculate the address to use to access a specified
- * register. This is only used for unusual access, mostly this is done
- * through the assembler access routines.
- */
-#define SC26198_PORTREG(port,reg) ((((port) & 0x07) << 4) | (reg))
-
-/*****************************************************************************/
-
-/*
- * Global configuration control register bit definitions.
- */
-#define GCCR_NOACK 0x00
-#define GCCR_IVRACK 0x02
-#define GCCR_IVRCHANACK 0x04
-#define GCCR_IVRTYPCHANACK 0x06
-#define GCCR_ASYNCCYCLE 0x00
-#define GCCR_SYNCCYCLE 0x40
-
-/*****************************************************************************/
-
-/*
- * Mode register 0 bit definitions.
- */
-#define MR0_ADDRNONE 0x00
-#define MR0_AUTOWAKE 0x01
-#define MR0_AUTODOZE 0x02
-#define MR0_AUTOWAKEDOZE 0x03
-#define MR0_SWFNONE 0x00
-#define MR0_SWFTX 0x04
-#define MR0_SWFRX 0x08
-#define MR0_SWFRXTX 0x0c
-#define MR0_TXMASK 0x30
-#define MR0_TXEMPTY 0x00
-#define MR0_TXHIGH 0x10
-#define MR0_TXHALF 0x20
-#define MR0_TXRDY 0x00
-#define MR0_ADDRNT 0x00
-#define MR0_ADDRT 0x40
-#define MR0_SWFNT 0x00
-#define MR0_SWFT 0x80
-
-/*
- * Mode register 1 bit definitions.
- */
-#define MR1_CS5 0x00
-#define MR1_CS6 0x01
-#define MR1_CS7 0x02
-#define MR1_CS8 0x03
-#define MR1_PAREVEN 0x00
-#define MR1_PARODD 0x04
-#define MR1_PARENB 0x00
-#define MR1_PARFORCE 0x08
-#define MR1_PARNONE 0x10
-#define MR1_PARSPECIAL 0x18
-#define MR1_ERRCHAR 0x00
-#define MR1_ERRBLOCK 0x20
-#define MR1_ISRUNMASKED 0x00
-#define MR1_ISRMASKED 0x40
-#define MR1_AUTORTS 0x80
-
-/*
- * Mode register 2 bit definitions.
- */
-#define MR2_STOP1 0x00
-#define MR2_STOP15 0x01
-#define MR2_STOP2 0x02
-#define MR2_STOP916 0x03
-#define MR2_RXFIFORDY 0x00
-#define MR2_RXFIFOHALF 0x04
-#define MR2_RXFIFOHIGH 0x08
-#define MR2_RXFIFOFULL 0x0c
-#define MR2_AUTOCTS 0x10
-#define MR2_TXRTS 0x20
-#define MR2_MODENORM 0x00
-#define MR2_MODEAUTOECHO 0x40
-#define MR2_MODELOOP 0x80
-#define MR2_MODEREMECHO 0xc0
-
-/*****************************************************************************/
-
-/*
- * Baud Rate Generator (BRG) selector values.
- */
-#define BRG_50 0x00
-#define BRG_75 0x01
-#define BRG_150 0x02
-#define BRG_200 0x03
-#define BRG_300 0x04
-#define BRG_450 0x05
-#define BRG_600 0x06
-#define BRG_900 0x07
-#define BRG_1200 0x08
-#define BRG_1800 0x09
-#define BRG_2400 0x0a
-#define BRG_3600 0x0b
-#define BRG_4800 0x0c
-#define BRG_7200 0x0d
-#define BRG_9600 0x0e
-#define BRG_14400 0x0f
-#define BRG_19200 0x10
-#define BRG_28200 0x11
-#define BRG_38400 0x12
-#define BRG_57600 0x13
-#define BRG_115200 0x14
-#define BRG_230400 0x15
-#define BRG_GIN0 0x16
-#define BRG_GIN1 0x17
-#define BRG_CT0 0x18
-#define BRG_CT1 0x19
-#define BRG_RX2TX316 0x1b
-#define BRG_RX2TX31 0x1c
-
-#define SC26198_MAXBAUD 921600
-
-/*****************************************************************************/
-
-/*
- * Command register command definitions.
- */
-#define CR_NULL 0x04
-#define CR_ADDRNORMAL 0x0c
-#define CR_RXRESET 0x14
-#define CR_TXRESET 0x1c
-#define CR_CLEARRXERR 0x24
-#define CR_BREAKRESET 0x2c
-#define CR_TXSTARTBREAK 0x34
-#define CR_TXSTOPBREAK 0x3c
-#define CR_RTSON 0x44
-#define CR_RTSOFF 0x4c
-#define CR_ADDRINIT 0x5c
-#define CR_RXERRBLOCK 0x6c
-#define CR_TXSENDXON 0x84
-#define CR_TXSENDXOFF 0x8c
-#define CR_GANGXONSET 0x94
-#define CR_GANGXOFFSET 0x9c
-#define CR_GANGXONINIT 0xa4
-#define CR_GANGXOFFINIT 0xac
-#define CR_HOSTXON 0xb4
-#define CR_HOSTXOFF 0xbc
-#define CR_CANCELXOFF 0xc4
-#define CR_ADDRRESET 0xdc
-#define CR_RESETALLPORTS 0xf4
-#define CR_RESETALL 0xfc
-
-#define CR_RXENABLE 0x01
-#define CR_TXENABLE 0x02
-
-/*****************************************************************************/
-
-/*
- * Channel status register.
- */
-#define SR_RXRDY 0x01
-#define SR_RXFULL 0x02
-#define SR_TXRDY 0x04
-#define SR_TXEMPTY 0x08
-#define SR_RXOVERRUN 0x10
-#define SR_RXPARITY 0x20
-#define SR_RXFRAMING 0x40
-#define SR_RXBREAK 0x80
-
-#define SR_RXERRS (SR_RXPARITY | SR_RXFRAMING | SR_RXOVERRUN)
-
-/*****************************************************************************/
-
-/*
- * Interrupt status register and interrupt mask register bit definitions.
- */
-#define IR_TXRDY 0x01
-#define IR_RXRDY 0x02
-#define IR_RXBREAK 0x04
-#define IR_XONXOFF 0x10
-#define IR_ADDRRECOG 0x20
-#define IR_RXWATCHDOG 0x40
-#define IR_IOPORT 0x80
-
-/*****************************************************************************/
-
-/*
- * Interrupt vector register field definitions.
- */
-#define IVR_CHANMASK 0x07
-#define IVR_TYPEMASK 0x18
-#define IVR_CONSTMASK 0xc0
-
-#define IVR_RXDATA 0x10
-#define IVR_RXBADDATA 0x18
-#define IVR_TXDATA 0x08
-#define IVR_OTHER 0x00
-
-/*****************************************************************************/
-
-/*
- * BRG timer control register bit definitions.
- */
-#define BRGCTCR_DISABCLK0 0x00
-#define BRGCTCR_ENABCLK0 0x08
-#define BRGCTCR_DISABCLK1 0x00
-#define BRGCTCR_ENABCLK1 0x80
-
-#define BRGCTCR_0SCLK16 0x00
-#define BRGCTCR_0SCLK32 0x01
-#define BRGCTCR_0SCLK64 0x02
-#define BRGCTCR_0SCLK128 0x03
-#define BRGCTCR_0X1 0x04
-#define BRGCTCR_0X12 0x05
-#define BRGCTCR_0IO1A 0x06
-#define BRGCTCR_0GIN0 0x07
-
-#define BRGCTCR_1SCLK16 0x00
-#define BRGCTCR_1SCLK32 0x10
-#define BRGCTCR_1SCLK64 0x20
-#define BRGCTCR_1SCLK128 0x30
-#define BRGCTCR_1X1 0x40
-#define BRGCTCR_1X12 0x50
-#define BRGCTCR_1IO1B 0x60
-#define BRGCTCR_1GIN1 0x70
-
-/*****************************************************************************/
-
-/*
- * Watch dog timer enable register.
- */
-#define WDTRCR_ENABALL 0xff
-
-/*****************************************************************************/
-
-/*
- * XON/XOFF interrupt status register.
- */
-#define XISR_TXCHARMASK 0x03
-#define XISR_TXCHARNORMAL 0x00
-#define XISR_TXWAIT 0x01
-#define XISR_TXXOFFPEND 0x02
-#define XISR_TXXONPEND 0x03
-
-#define XISR_TXFLOWMASK 0x0c
-#define XISR_TXNORMAL 0x00
-#define XISR_TXSTOPPEND 0x04
-#define XISR_TXSTARTED 0x08
-#define XISR_TXSTOPPED 0x0c
-
-#define XISR_RXFLOWMASK 0x30
-#define XISR_RXFLOWNONE 0x00
-#define XISR_RXXONSENT 0x10
-#define XISR_RXXOFFSENT 0x20
-
-#define XISR_RXXONGOT 0x40
-#define XISR_RXXOFFGOT 0x80
-
-/*****************************************************************************/
-
-/*
- * Current interrupt register.
- */
-#define CIR_TYPEMASK 0xc0
-#define CIR_TYPEOTHER 0x00
-#define CIR_TYPETX 0x40
-#define CIR_TYPERXGOOD 0x80
-#define CIR_TYPERXBAD 0xc0
-
-#define CIR_RXDATA 0x80
-#define CIR_RXBADDATA 0x40
-#define CIR_TXDATA 0x40
-
-#define CIR_CHANMASK 0x07
-#define CIR_CNTMASK 0x38
-
-#define CIR_SUBTYPEMASK 0x38
-#define CIR_SUBNONE 0x00
-#define CIR_SUBCOS 0x08
-#define CIR_SUBADDR 0x10
-#define CIR_SUBXONXOFF 0x18
-#define CIR_SUBBREAK 0x28
-
-/*****************************************************************************/
-
-/*
- * Global interrupting channel register.
- */
-#define GICR_CHANMASK 0x07
-
-/*****************************************************************************/
-
-/*
- * Global interrupting byte count register.
- */
-#define GICR_COUNTMASK 0x0f
-
-/*****************************************************************************/
-
-/*
- * Global interrupting type register.
- */
-#define GITR_RXMASK 0xc0
-#define GITR_RXNONE 0x00
-#define GITR_RXBADDATA 0x80
-#define GITR_RXGOODDATA 0xc0
-#define GITR_TXDATA 0x20
-
-#define GITR_SUBTYPEMASK 0x07
-#define GITR_SUBNONE 0x00
-#define GITR_SUBCOS 0x01
-#define GITR_SUBADDR 0x02
-#define GITR_SUBXONXOFF 0x03
-#define GITR_SUBBREAK 0x05
-
-/*****************************************************************************/
-
-/*
- * Input port change register.
- */
-#define IPR_CTS 0x01
-#define IPR_DTR 0x02
-#define IPR_RTS 0x04
-#define IPR_DCD 0x08
-#define IPR_CTSCHANGE 0x10
-#define IPR_DTRCHANGE 0x20
-#define IPR_RTSCHANGE 0x40
-#define IPR_DCDCHANGE 0x80
-
-#define IPR_CHANGEMASK 0xf0
-
-/*****************************************************************************/
-
-/*
- * IO port interrupt and output register.
- */
-#define IOPR_CTS 0x01
-#define IOPR_DTR 0x02
-#define IOPR_RTS 0x04
-#define IOPR_DCD 0x08
-#define IOPR_CTSCOS 0x10
-#define IOPR_DTRCOS 0x20
-#define IOPR_RTSCOS 0x40
-#define IOPR_DCDCOS 0x80
-
-/*****************************************************************************/
-
-/*
- * IO port configuration register.
- */
-#define IOPCR_SETCTS 0x00
-#define IOPCR_SETDTR 0x04
-#define IOPCR_SETRTS 0x10
-#define IOPCR_SETDCD 0x00
-
-#define IOPCR_SETSIGS (IOPCR_SETRTS | IOPCR_SETRTS | IOPCR_SETDTR | IOPCR_SETDCD)
-
-/*****************************************************************************/
-
-/*
- * General purpose output select register.
- */
-#define GPORS_TXC1XA 0x08
-#define GPORS_TXC16XA 0x09
-#define GPORS_RXC16XA 0x0a
-#define GPORS_TXC16XB 0x0b
-#define GPORS_GPOR3 0x0c
-#define GPORS_GPOR2 0x0d
-#define GPORS_GPOR1 0x0e
-#define GPORS_GPOR0 0x0f
-
-/*****************************************************************************/
-
-/*
- * General purpose output register.
- */
-#define GPOR_0 0x01
-#define GPOR_1 0x02
-#define GPOR_2 0x04
-#define GPOR_3 0x08
-
-/*****************************************************************************/
-
-/*
- * General purpose output clock register.
- */
-#define GPORC_0NONE 0x00
-#define GPORC_0GIN0 0x01
-#define GPORC_0GIN1 0x02
-#define GPORC_0IO3A 0x02
-
-#define GPORC_1NONE 0x00
-#define GPORC_1GIN0 0x04
-#define GPORC_1GIN1 0x08
-#define GPORC_1IO3C 0x0c
-
-#define GPORC_2NONE 0x00
-#define GPORC_2GIN0 0x10
-#define GPORC_2GIN1 0x20
-#define GPORC_2IO3E 0x20
-
-#define GPORC_3NONE 0x00
-#define GPORC_3GIN0 0x40
-#define GPORC_3GIN1 0x80
-#define GPORC_3IO3G 0xc0
-
-/*****************************************************************************/
-
-/*
- * General purpose output data register.
- */
-#define GPOD_0MASK 0x03
-#define GPOD_0SET1 0x00
-#define GPOD_0SET0 0x01
-#define GPOD_0SETR0 0x02
-#define GPOD_0SETIO3B 0x03
-
-#define GPOD_1MASK 0x0c
-#define GPOD_1SET1 0x00
-#define GPOD_1SET0 0x04
-#define GPOD_1SETR0 0x08
-#define GPOD_1SETIO3D 0x0c
-
-#define GPOD_2MASK 0x30
-#define GPOD_2SET1 0x00
-#define GPOD_2SET0 0x10
-#define GPOD_2SETR0 0x20
-#define GPOD_2SETIO3F 0x30
-
-#define GPOD_3MASK 0xc0
-#define GPOD_3SET1 0x00
-#define GPOD_3SET0 0x40
-#define GPOD_3SETR0 0x80
-#define GPOD_3SETIO3H 0xc0
-
-/*****************************************************************************/
-#endif
diff --git a/include/linux/serial.h b/include/linux/serial.h
index 90e9f981358a..861e51de476b 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -12,9 +12,12 @@
#include <linux/types.h>
+#include <linux/tty_flags.h>
+
#ifdef __KERNEL__
#include <asm/page.h>
+
/*
* Counters of the input lines (CTS, DSR, RI, CD) interrupts
*/
@@ -83,89 +86,11 @@ struct serial_struct {
#define SERIAL_IO_HUB6 1
#define SERIAL_IO_MEM 2
-struct serial_uart_config {
- char *name;
- int dfl_xmit_fifo_size;
- int flags;
-};
-
#define UART_CLEAR_FIFO 0x01
#define UART_USE_FIFO 0x02
#define UART_STARTECH 0x04
#define UART_NATSEMI 0x08
-/*
- * Definitions for async_struct (and serial_struct) flags field
- *
- * Define ASYNCB_* for convenient use with {test,set,clear}_bit.
- */
-#define ASYNCB_HUP_NOTIFY 0 /* Notify getty on hangups and closes
- * on the callout port */
-#define ASYNCB_FOURPORT 1 /* Set OU1, OUT2 per AST Fourport settings */
-#define ASYNCB_SAK 2 /* Secure Attention Key (Orange book) */
-#define ASYNCB_SPLIT_TERMIOS 3 /* Separate termios for dialin/callout */
-#define ASYNCB_SPD_HI 4 /* Use 56000 instead of 38400 bps */
-#define ASYNCB_SPD_VHI 5 /* Use 115200 instead of 38400 bps */
-#define ASYNCB_SKIP_TEST 6 /* Skip UART test during autoconfiguration */
-#define ASYNCB_AUTO_IRQ 7 /* Do automatic IRQ during
- * autoconfiguration */
-#define ASYNCB_SESSION_LOCKOUT 8 /* Lock out cua opens based on session */
-#define ASYNCB_PGRP_LOCKOUT 9 /* Lock out cua opens based on pgrp */
-#define ASYNCB_CALLOUT_NOHUP 10 /* Don't do hangups for cua device */
-#define ASYNCB_HARDPPS_CD 11 /* Call hardpps when CD goes high */
-#define ASYNCB_SPD_SHI 12 /* Use 230400 instead of 38400 bps */
-#define ASYNCB_LOW_LATENCY 13 /* Request low latency behaviour */
-#define ASYNCB_BUGGY_UART 14 /* This is a buggy UART, skip some safety
- * checks. Note: can be dangerous! */
-#define ASYNCB_AUTOPROBE 15 /* Port was autoprobed by PCI or PNP code */
-#define ASYNCB_LAST_USER 15
-
-/* Internal flags used only by kernel */
-#define ASYNCB_INITIALIZED 31 /* Serial port was initialized */
-#define ASYNCB_SUSPENDED 30 /* Serial port is suspended */
-#define ASYNCB_NORMAL_ACTIVE 29 /* Normal device is active */
-#define ASYNCB_BOOT_AUTOCONF 28 /* Autoconfigure port on bootup */
-#define ASYNCB_CLOSING 27 /* Serial port is closing */
-#define ASYNCB_CTS_FLOW 26 /* Do CTS flow control */
-#define ASYNCB_CHECK_CD 25 /* i.e., CLOCAL */
-#define ASYNCB_SHARE_IRQ 24 /* for multifunction cards, no longer used */
-#define ASYNCB_CONS_FLOW 23 /* flow control for console */
-#define ASYNCB_FIRST_KERNEL 22
-
-#define ASYNC_HUP_NOTIFY (1U << ASYNCB_HUP_NOTIFY)
-#define ASYNC_SUSPENDED (1U << ASYNCB_SUSPENDED)
-#define ASYNC_FOURPORT (1U << ASYNCB_FOURPORT)
-#define ASYNC_SAK (1U << ASYNCB_SAK)
-#define ASYNC_SPLIT_TERMIOS (1U << ASYNCB_SPLIT_TERMIOS)
-#define ASYNC_SPD_HI (1U << ASYNCB_SPD_HI)
-#define ASYNC_SPD_VHI (1U << ASYNCB_SPD_VHI)
-#define ASYNC_SKIP_TEST (1U << ASYNCB_SKIP_TEST)
-#define ASYNC_AUTO_IRQ (1U << ASYNCB_AUTO_IRQ)
-#define ASYNC_SESSION_LOCKOUT (1U << ASYNCB_SESSION_LOCKOUT)
-#define ASYNC_PGRP_LOCKOUT (1U << ASYNCB_PGRP_LOCKOUT)
-#define ASYNC_CALLOUT_NOHUP (1U << ASYNCB_CALLOUT_NOHUP)
-#define ASYNC_HARDPPS_CD (1U << ASYNCB_HARDPPS_CD)
-#define ASYNC_SPD_SHI (1U << ASYNCB_SPD_SHI)
-#define ASYNC_LOW_LATENCY (1U << ASYNCB_LOW_LATENCY)
-#define ASYNC_BUGGY_UART (1U << ASYNCB_BUGGY_UART)
-#define ASYNC_AUTOPROBE (1U << ASYNCB_AUTOPROBE)
-
-#define ASYNC_FLAGS ((1U << (ASYNCB_LAST_USER + 1)) - 1)
-#define ASYNC_USR_MASK (ASYNC_SPD_MASK|ASYNC_CALLOUT_NOHUP| \
- ASYNC_LOW_LATENCY)
-#define ASYNC_SPD_CUST (ASYNC_SPD_HI|ASYNC_SPD_VHI)
-#define ASYNC_SPD_WARP (ASYNC_SPD_HI|ASYNC_SPD_SHI)
-#define ASYNC_SPD_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI)
-
-#define ASYNC_INITIALIZED (1U << ASYNCB_INITIALIZED)
-#define ASYNC_NORMAL_ACTIVE (1U << ASYNCB_NORMAL_ACTIVE)
-#define ASYNC_BOOT_AUTOCONF (1U << ASYNCB_BOOT_AUTOCONF)
-#define ASYNC_CLOSING (1U << ASYNCB_CLOSING)
-#define ASYNC_CTS_FLOW (1U << ASYNCB_CTS_FLOW)
-#define ASYNC_CHECK_CD (1U << ASYNCB_CHECK_CD)
-#define ASYNC_SHARE_IRQ (1U << ASYNCB_SHARE_IRQ)
-#define ASYNC_CONS_FLOW (1U << ASYNCB_CONS_FLOW)
-#define ASYNC_INTERNAL_FLAGS (~((1U << ASYNCB_FIRST_KERNEL) - 1))
/*
* Multiport serial configuration structure --- external structure
diff --git a/include/linux/serial167.h b/include/linux/serial167.h
deleted file mode 100644
index 59c81b708562..000000000000
--- a/include/linux/serial167.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * serial167.h
- *
- * Richard Hirst [richard@sleepie.demon.co.uk]
- *
- * Based on cyclades.h
- */
-
-struct cyclades_monitor {
- unsigned long int_count;
- unsigned long char_count;
- unsigned long char_max;
- unsigned long char_last;
-};
-
-/*
- * This is our internal structure for each serial port's state.
- *
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-struct cyclades_port {
- int magic;
- int type;
- int card;
- int line;
- int flags; /* defined in tty.h */
- struct tty_struct *tty;
- int read_status_mask;
- int timeout;
- int xmit_fifo_size;
- int cor1,cor2,cor3,cor4,cor5,cor6,cor7;
- int tbpr,tco,rbpr,rco;
- int ignore_status_mask;
- int close_delay;
- int IER; /* Interrupt Enable Register */
- unsigned long last_active;
- int count; /* # of fd on device */
- int x_char; /* to be pushed out ASAP */
- int x_break;
- int blocked_open; /* # of blocked opens */
- unsigned char *xmit_buf;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
- int default_threshold;
- int default_timeout;
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
- struct cyclades_monitor mon;
-};
-
-#define CYCLADES_MAGIC 0x4359
-
-#define CYGETMON 0x435901
-#define CYGETTHRESH 0x435902
-#define CYSETTHRESH 0x435903
-#define CYGETDEFTHRESH 0x435904
-#define CYSETDEFTHRESH 0x435905
-#define CYGETTIMEOUT 0x435906
-#define CYSETTIMEOUT 0x435907
-#define CYGETDEFTIMEOUT 0x435908
-#define CYSETDEFTIMEOUT 0x435909
-
-#define CyMaxChipsPerCard 1
-
-/**** cd2401 registers ****/
-
-#define CyGFRCR (0x81)
-#define CyCCR (0x13)
-#define CyCLR_CHAN (0x40)
-#define CyINIT_CHAN (0x20)
-#define CyCHIP_RESET (0x10)
-#define CyENB_XMTR (0x08)
-#define CyDIS_XMTR (0x04)
-#define CyENB_RCVR (0x02)
-#define CyDIS_RCVR (0x01)
-#define CyCAR (0xee)
-#define CyIER (0x11)
-#define CyMdmCh (0x80)
-#define CyRxExc (0x20)
-#define CyRxData (0x08)
-#define CyTxMpty (0x02)
-#define CyTxRdy (0x01)
-#define CyLICR (0x26)
-#define CyRISR (0x89)
-#define CyTIMEOUT (0x80)
-#define CySPECHAR (0x70)
-#define CyOVERRUN (0x08)
-#define CyPARITY (0x04)
-#define CyFRAME (0x02)
-#define CyBREAK (0x01)
-#define CyREOIR (0x84)
-#define CyTEOIR (0x85)
-#define CyMEOIR (0x86)
-#define CyNOTRANS (0x08)
-#define CyRFOC (0x30)
-#define CyRDR (0xf8)
-#define CyTDR (0xf8)
-#define CyMISR (0x8b)
-#define CyRISR (0x89)
-#define CyTISR (0x8a)
-#define CyMSVR1 (0xde)
-#define CyMSVR2 (0xdf)
-#define CyDSR (0x80)
-#define CyDCD (0x40)
-#define CyCTS (0x20)
-#define CyDTR (0x02)
-#define CyRTS (0x01)
-#define CyRTPRL (0x25)
-#define CyRTPRH (0x24)
-#define CyCOR1 (0x10)
-#define CyPARITY_NONE (0x00)
-#define CyPARITY_E (0x40)
-#define CyPARITY_O (0xC0)
-#define Cy_5_BITS (0x04)
-#define Cy_6_BITS (0x05)
-#define Cy_7_BITS (0x06)
-#define Cy_8_BITS (0x07)
-#define CyCOR2 (0x17)
-#define CyETC (0x20)
-#define CyCtsAE (0x02)
-#define CyCOR3 (0x16)
-#define Cy_1_STOP (0x02)
-#define Cy_2_STOP (0x04)
-#define CyCOR4 (0x15)
-#define CyREC_FIFO (0x0F) /* Receive FIFO threshold */
-#define CyCOR5 (0x14)
-#define CyCOR6 (0x18)
-#define CyCOR7 (0x07)
-#define CyRBPR (0xcb)
-#define CyRCOR (0xc8)
-#define CyTBPR (0xc3)
-#define CyTCOR (0xc0)
-#define CySCHR1 (0x1f)
-#define CySCHR2 (0x1e)
-#define CyTPR (0xda)
-#define CyPILR1 (0xe3)
-#define CyPILR2 (0xe0)
-#define CyPILR3 (0xe1)
-#define CyCMR (0x1b)
-#define CyASYNC (0x02)
-#define CyLICR (0x26)
-#define CyLIVR (0x09)
-#define CySCRL (0x23)
-#define CySCRH (0x22)
-#define CyTFTC (0x80)
-
-
-/* max number of chars in the FIFO */
-
-#define CyMAX_CHAR_FIFO 12
-
-/***************************************************************************/
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index a416e92012ef..c174c90fb3fb 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -65,11 +65,38 @@ enum {
* platform device. Using these will make your driver
* dependent on the 8250 driver.
*/
-struct uart_port;
-struct uart_8250_port;
+
+struct uart_8250_port {
+ struct uart_port port;
+ struct timer_list timer; /* "no irq" timer */
+ struct list_head list; /* ports on this IRQ */
+ unsigned short capabilities; /* port capabilities */
+ unsigned short bugs; /* port bugs */
+ unsigned int tx_loadsz; /* transmit fifo load size */
+ unsigned char acr;
+ unsigned char ier;
+ unsigned char lcr;
+ unsigned char mcr;
+ unsigned char mcr_mask; /* mask of user bits */
+ unsigned char mcr_force; /* mask of forced bits */
+ unsigned char cur_iotype; /* Running I/O type */
+
+ /*
+ * Some bits in registers are cleared on a read, so they must
+ * be saved whenever the register is read but the bits will not
+ * be immediately processed.
+ */
+#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
+ unsigned char lsr_saved_flags;
+#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
+ unsigned char msr_saved_flags;
+
+ /* 8250 specific callbacks */
+ int (*dl_read)(struct uart_8250_port *);
+ void (*dl_write)(struct uart_8250_port *, int);
+};
int serial8250_register_8250_port(struct uart_8250_port *);
-int serial8250_register_port(struct uart_port *);
void serial8250_unregister_port(int line);
void serial8250_suspend_port(int line);
void serial8250_resume_port(int line);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 0253c2022e53..f9b22ec7a9f3 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -48,7 +48,8 @@
#define PORT_TEGRA 20 /* NVIDIA Tegra internal UART */
#define PORT_XR17D15X 21 /* Exar XR17D15x UART */
#define PORT_LPC3220 22 /* NXP LPC32xx SoC "Standard" UART */
-#define PORT_MAX_8250 22 /* max port ID */
+#define PORT_8250_CIR 23 /* CIR infrared port, has its own driver */
+#define PORT_MAX_8250 23 /* max port ID */
/*
* ARM specific type numbers. These are not currently guaranteed
@@ -193,8 +194,8 @@
/* SH-SCI */
#define PORT_SCIFB 93
-/* MAX3107 */
-#define PORT_MAX3107 94
+/* MAX310X */
+#define PORT_MAX310X 94
/* High Speed UART for Medfield */
#define PORT_MFD 95
@@ -274,6 +275,7 @@ struct uart_ops {
int (*verify_port)(struct uart_port *, struct serial_struct *);
int (*ioctl)(struct uart_port *, unsigned int, unsigned long);
#ifdef CONFIG_CONSOLE_POLL
+ int (*poll_init)(struct uart_port *);
void (*poll_put_char)(struct uart_port *, unsigned char);
int (*poll_get_char)(struct uart_port *);
#endif
diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h
index 8ce70d76f836..5ed325e88a81 100644
--- a/include/linux/serial_reg.h
+++ b/include/linux/serial_reg.h
@@ -40,6 +40,10 @@
#define UART_IIR_BUSY 0x07 /* DesignWare APB Busy Detect */
+#define UART_IIR_RX_TIMEOUT 0x0c /* OMAP RX Timeout interrupt */
+#define UART_IIR_XOFF 0x10 /* OMAP XOFF/Special Character */
+#define UART_IIR_CTS_RTS_DSR 0x20 /* OMAP CTS/RTS/DSR Change */
+
#define UART_FCR 2 /* Out: FIFO Control Register */
#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */
#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */
diff --git a/include/linux/stallion.h b/include/linux/stallion.h
deleted file mode 100644
index 336af33c6ea4..000000000000
--- a/include/linux/stallion.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*****************************************************************************/
-
-/*
- * stallion.h -- stallion multiport serial driver.
- *
- * Copyright (C) 1996-1998 Stallion Technologies
- * Copyright (C) 1994-1996 Greg Ungerer.
- *
- * 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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*****************************************************************************/
-#ifndef _STALLION_H
-#define _STALLION_H
-/*****************************************************************************/
-
-/*
- * Define important driver constants here.
- */
-#define STL_MAXBRDS 4
-#define STL_MAXPANELS 4
-#define STL_MAXBANKS 8
-#define STL_PORTSPERPANEL 16
-#define STL_MAXPORTS 64
-#define STL_MAXDEVS (STL_MAXBRDS * STL_MAXPORTS)
-
-
-/*
- * Define a set of structures to hold all the board/panel/port info
- * for our ports. These will be dynamically allocated as required.
- */
-
-/*
- * Define a ring queue structure for each port. This will hold the
- * TX data waiting to be output. Characters are fed into this buffer
- * from the line discipline (or even direct from user space!) and
- * then fed into the UARTs during interrupts. Will use a classic ring
- * queue here for this. The good thing about this type of ring queue
- * is that the head and tail pointers can be updated without interrupt
- * protection - since "write" code only needs to change the head, and
- * interrupt code only needs to change the tail.
- */
-struct stlrq {
- char *buf;
- char *head;
- char *tail;
-};
-
-/*
- * Port, panel and board structures to hold status info about each.
- * The board structure contains pointers to structures for each panel
- * connected to it, and in turn each panel structure contains pointers
- * for each port structure for each port on that panel. Note that
- * the port structure also contains the board and panel number that it
- * is associated with, this makes it (fairly) easy to get back to the
- * board/panel info for a port.
- */
-struct stlport {
- unsigned long magic;
- struct tty_port port;
- unsigned int portnr;
- unsigned int panelnr;
- unsigned int brdnr;
- int ioaddr;
- int uartaddr;
- unsigned int pagenr;
- unsigned long istate;
- int baud_base;
- int custom_divisor;
- int close_delay;
- int closing_wait;
- int openwaitcnt;
- int brklen;
- unsigned int sigs;
- unsigned int rxignoremsk;
- unsigned int rxmarkmsk;
- unsigned int imr;
- unsigned int crenable;
- unsigned long clk;
- unsigned long hwid;
- void *uartp;
- comstats_t stats;
- struct stlrq tx;
-};
-
-struct stlpanel {
- unsigned long magic;
- unsigned int panelnr;
- unsigned int brdnr;
- unsigned int pagenr;
- unsigned int nrports;
- int iobase;
- void *uartp;
- void (*isr)(struct stlpanel *panelp, unsigned int iobase);
- unsigned int hwid;
- unsigned int ackmask;
- struct stlport *ports[STL_PORTSPERPANEL];
-};
-
-struct stlbrd {
- unsigned long magic;
- unsigned int brdnr;
- unsigned int brdtype;
- unsigned int state;
- unsigned int nrpanels;
- unsigned int nrports;
- unsigned int nrbnks;
- int irq;
- int irqtype;
- int (*isr)(struct stlbrd *brdp);
- unsigned int ioaddr1;
- unsigned int ioaddr2;
- unsigned int iosize1;
- unsigned int iosize2;
- unsigned int iostatus;
- unsigned int ioctrl;
- unsigned int ioctrlval;
- unsigned int hwid;
- unsigned long clk;
- unsigned int bnkpageaddr[STL_MAXBANKS];
- unsigned int bnkstataddr[STL_MAXBANKS];
- struct stlpanel *bnk2panel[STL_MAXBANKS];
- struct stlpanel *panels[STL_MAXPANELS];
-};
-
-
-/*
- * Define MAGIC numbers used for above structures.
- */
-#define STL_PORTMAGIC 0x5a7182c9
-#define STL_PANELMAGIC 0x7ef621a1
-#define STL_BOARDMAGIC 0xa2267f52
-
-/*****************************************************************************/
-#endif
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 9f47ab540f65..1509b86825d8 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -43,6 +43,7 @@
#include <linux/tty_driver.h>
#include <linux/tty_ldisc.h>
#include <linux/mutex.h>
+#include <linux/tty_flags.h>
@@ -103,28 +104,28 @@ struct tty_bufhead {
#define TTY_PARITY 3
#define TTY_OVERRUN 4
-#define INTR_CHAR(tty) ((tty)->termios->c_cc[VINTR])
-#define QUIT_CHAR(tty) ((tty)->termios->c_cc[VQUIT])
-#define ERASE_CHAR(tty) ((tty)->termios->c_cc[VERASE])
-#define KILL_CHAR(tty) ((tty)->termios->c_cc[VKILL])
-#define EOF_CHAR(tty) ((tty)->termios->c_cc[VEOF])
-#define TIME_CHAR(tty) ((tty)->termios->c_cc[VTIME])
-#define MIN_CHAR(tty) ((tty)->termios->c_cc[VMIN])
-#define SWTC_CHAR(tty) ((tty)->termios->c_cc[VSWTC])
-#define START_CHAR(tty) ((tty)->termios->c_cc[VSTART])
-#define STOP_CHAR(tty) ((tty)->termios->c_cc[VSTOP])
-#define SUSP_CHAR(tty) ((tty)->termios->c_cc[VSUSP])
-#define EOL_CHAR(tty) ((tty)->termios->c_cc[VEOL])
-#define REPRINT_CHAR(tty) ((tty)->termios->c_cc[VREPRINT])
-#define DISCARD_CHAR(tty) ((tty)->termios->c_cc[VDISCARD])
-#define WERASE_CHAR(tty) ((tty)->termios->c_cc[VWERASE])
-#define LNEXT_CHAR(tty) ((tty)->termios->c_cc[VLNEXT])
-#define EOL2_CHAR(tty) ((tty)->termios->c_cc[VEOL2])
-
-#define _I_FLAG(tty, f) ((tty)->termios->c_iflag & (f))
-#define _O_FLAG(tty, f) ((tty)->termios->c_oflag & (f))
-#define _C_FLAG(tty, f) ((tty)->termios->c_cflag & (f))
-#define _L_FLAG(tty, f) ((tty)->termios->c_lflag & (f))
+#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR])
+#define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT])
+#define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE])
+#define KILL_CHAR(tty) ((tty)->termios.c_cc[VKILL])
+#define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF])
+#define TIME_CHAR(tty) ((tty)->termios.c_cc[VTIME])
+#define MIN_CHAR(tty) ((tty)->termios.c_cc[VMIN])
+#define SWTC_CHAR(tty) ((tty)->termios.c_cc[VSWTC])
+#define START_CHAR(tty) ((tty)->termios.c_cc[VSTART])
+#define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP])
+#define SUSP_CHAR(tty) ((tty)->termios.c_cc[VSUSP])
+#define EOL_CHAR(tty) ((tty)->termios.c_cc[VEOL])
+#define REPRINT_CHAR(tty) ((tty)->termios.c_cc[VREPRINT])
+#define DISCARD_CHAR(tty) ((tty)->termios.c_cc[VDISCARD])
+#define WERASE_CHAR(tty) ((tty)->termios.c_cc[VWERASE])
+#define LNEXT_CHAR(tty) ((tty)->termios.c_cc[VLNEXT])
+#define EOL2_CHAR(tty) ((tty)->termios.c_cc[VEOL2])
+
+#define _I_FLAG(tty, f) ((tty)->termios.c_iflag & (f))
+#define _O_FLAG(tty, f) ((tty)->termios.c_oflag & (f))
+#define _C_FLAG(tty, f) ((tty)->termios.c_cflag & (f))
+#define _L_FLAG(tty, f) ((tty)->termios.c_lflag & (f))
#define I_IGNBRK(tty) _I_FLAG((tty), IGNBRK)
#define I_BRKINT(tty) _I_FLAG((tty), BRKINT)
@@ -268,10 +269,11 @@ struct tty_struct {
struct mutex ldisc_mutex;
struct tty_ldisc *ldisc;
+ struct mutex legacy_mutex;
struct mutex termios_mutex;
spinlock_t ctrl_lock;
/* Termios values are protected by the termios mutex */
- struct ktermios *termios, *termios_locked;
+ struct ktermios termios, termios_locked;
struct termiox *termiox; /* May be NULL for unsupported */
char name[64];
struct pid *pgrp; /* Protected by ctrl lock */
@@ -410,6 +412,10 @@ extern int tty_register_driver(struct tty_driver *driver);
extern int tty_unregister_driver(struct tty_driver *driver);
extern struct device *tty_register_device(struct tty_driver *driver,
unsigned index, struct device *dev);
+extern struct device *tty_register_device_attr(struct tty_driver *driver,
+ unsigned index, struct device *device,
+ void *drvdata,
+ const struct attribute_group **attr_grp);
extern void tty_unregister_device(struct tty_driver *driver, unsigned index);
extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
int buflen);
@@ -423,7 +429,6 @@ extern void tty_unthrottle(struct tty_struct *tty);
extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
extern void tty_driver_remove_tty(struct tty_driver *driver,
struct tty_struct *tty);
-extern void tty_shutdown(struct tty_struct *tty);
extern void tty_free_termios(struct tty_struct *tty);
extern int is_current_pgrp_orphaned(void);
extern struct pid *tty_get_pgrp(struct tty_struct *tty);
@@ -497,6 +502,15 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay);
#define tty_is_writelocked(tty) (mutex_is_locked(&tty->atomic_write_lock))
extern void tty_port_init(struct tty_port *port);
+extern void tty_port_link_device(struct tty_port *port,
+ struct tty_driver *driver, unsigned index);
+extern struct device *tty_port_register_device(struct tty_port *port,
+ struct tty_driver *driver, unsigned index,
+ struct device *device);
+extern struct device *tty_port_register_device_attr(struct tty_port *port,
+ struct tty_driver *driver, unsigned index,
+ struct device *device, void *drvdata,
+ const struct attribute_group **attr_grp);
extern int tty_port_alloc_xmit_buf(struct tty_port *port);
extern void tty_port_free_xmit_buf(struct tty_port *port);
extern void tty_port_put(struct tty_port *port);
@@ -508,6 +522,12 @@ static inline struct tty_port *tty_port_get(struct tty_port *port)
return port;
}
+/* If the cts flow control is enabled, return true. */
+static inline bool tty_port_cts_enabled(struct tty_port *port)
+{
+ return port->flags & ASYNC_CTS_FLOW;
+}
+
extern struct tty_struct *tty_port_tty_get(struct tty_port *port);
extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
extern int tty_port_carrier_raised(struct tty_port *port);
@@ -521,6 +541,8 @@ extern int tty_port_close_start(struct tty_port *port,
extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty);
extern void tty_port_close(struct tty_port *port,
struct tty_struct *tty, struct file *filp);
+extern int tty_port_install(struct tty_port *port, struct tty_driver *driver,
+ struct tty_struct *tty);
extern int tty_port_open(struct tty_port *port,
struct tty_struct *tty, struct file *filp);
static inline int tty_port_users(struct tty_port *port)
@@ -605,8 +627,12 @@ extern long vt_compat_ioctl(struct tty_struct *tty,
/* tty_mutex.c */
/* functions for preparation of BKL removal */
-extern void __lockfunc tty_lock(void) __acquires(tty_lock);
-extern void __lockfunc tty_unlock(void) __releases(tty_lock);
+extern void __lockfunc tty_lock(struct tty_struct *tty);
+extern void __lockfunc tty_unlock(struct tty_struct *tty);
+extern void __lockfunc tty_lock_pair(struct tty_struct *tty,
+ struct tty_struct *tty2);
+extern void __lockfunc tty_unlock_pair(struct tty_struct *tty,
+ struct tty_struct *tty2);
/*
* this shall be called only from where BTM is held (like close)
@@ -621,9 +647,9 @@ extern void __lockfunc tty_unlock(void) __releases(tty_lock);
static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
long timeout)
{
- tty_unlock(); /* tty->ops->close holds the BTM, drop it while waiting */
+ tty_unlock(tty); /* tty->ops->close holds the BTM, drop it while waiting */
tty_wait_until_sent(tty, timeout);
- tty_lock();
+ tty_lock(tty);
}
/*
@@ -638,16 +664,16 @@ static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
*
* Do not use in new code.
*/
-#define wait_event_interruptible_tty(wq, condition) \
+#define wait_event_interruptible_tty(tty, wq, condition) \
({ \
int __ret = 0; \
if (!(condition)) { \
- __wait_event_interruptible_tty(wq, condition, __ret); \
+ __wait_event_interruptible_tty(tty, wq, condition, __ret); \
} \
__ret; \
})
-#define __wait_event_interruptible_tty(wq, condition, ret) \
+#define __wait_event_interruptible_tty(tty, wq, condition, ret) \
do { \
DEFINE_WAIT(__wait); \
\
@@ -656,9 +682,9 @@ do { \
if (condition) \
break; \
if (!signal_pending(current)) { \
- tty_unlock(); \
+ tty_unlock(tty); \
schedule(); \
- tty_lock(); \
+ tty_lock(tty); \
continue; \
} \
ret = -ERESTARTSYS; \
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 6e6dbb7447b6..dd976cfb6131 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -45,14 +45,9 @@
*
* void (*shutdown)(struct tty_struct * tty);
*
- * This routine is called synchronously when a particular tty device
- * is closed for the last time freeing up the resources.
- * Note that tty_shutdown() is not called if ops->shutdown is defined.
- * This means one is responsible to take care of calling ops->remove (e.g.
- * via tty_driver_remove_tty) and releasing tty->termios.
- * Note that this hook may be called from *all* the contexts where one
- * uses tty refcounting (e.g. tty_port_tty_get).
- *
+ * This routine is called under the tty lock when a particular tty device
+ * is closed for the last time. It executes before the tty resources
+ * are freed so may execute while another function holds a tty kref.
*
* void (*cleanup)(struct tty_struct * tty);
*
@@ -294,18 +289,18 @@ struct tty_operations {
struct tty_driver {
int magic; /* magic number for this structure */
struct kref kref; /* Reference management */
- struct cdev cdev;
+ struct cdev *cdevs;
struct module *owner;
const char *driver_name;
const char *name;
int name_base; /* offset of printed name */
int major; /* major device number */
int minor_start; /* start of minor device number */
- int num; /* number of devices allocated */
+ unsigned int num; /* number of devices allocated */
short type; /* type of tty driver */
short subtype; /* subtype of tty driver */
struct ktermios init_termios; /* Initial termios */
- int flags; /* tty driver flags */
+ unsigned long flags; /* tty driver flags */
struct proc_dir_entry *proc_entry; /* /proc fs entry */
struct tty_driver *other; /* only used for the PTY driver */
@@ -313,6 +308,7 @@ struct tty_driver {
* Pointer to the tty data structures
*/
struct tty_struct **ttys;
+ struct tty_port **ports;
struct ktermios **termios;
void *driver_state;
@@ -326,7 +322,8 @@ struct tty_driver {
extern struct list_head tty_drivers;
-extern struct tty_driver *__alloc_tty_driver(int lines, struct module *owner);
+extern struct tty_driver *__tty_alloc_driver(unsigned int lines,
+ struct module *owner, unsigned long flags);
extern void put_tty_driver(struct tty_driver *driver);
extern void tty_set_operations(struct tty_driver *driver,
const struct tty_operations *op);
@@ -334,7 +331,21 @@ extern struct tty_driver *tty_find_polling_driver(char *name, int *line);
extern void tty_driver_kref_put(struct tty_driver *driver);
-#define alloc_tty_driver(lines) __alloc_tty_driver(lines, THIS_MODULE)
+/* Use TTY_DRIVER_* flags below */
+#define tty_alloc_driver(lines, flags) \
+ __tty_alloc_driver(lines, THIS_MODULE, flags)
+
+/*
+ * DEPRECATED Do not use this in new code, use tty_alloc_driver instead.
+ * (And change the return value checks.)
+ */
+static inline struct tty_driver *alloc_tty_driver(unsigned int lines)
+{
+ struct tty_driver *ret = tty_alloc_driver(lines, 0);
+ if (IS_ERR(ret))
+ return NULL;
+ return ret;
+}
static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
{
@@ -380,6 +391,14 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
* the requested timeout to the caller instead of using a simple
* on/off interface.
*
+ * TTY_DRIVER_DYNAMIC_ALLOC -- do not allocate structures which are
+ * needed per line for this driver as it would waste memory.
+ * The driver will take care.
+ *
+ * TTY_DRIVER_UNNUMBERED_NODE -- do not create numbered /dev nodes. In
+ * other words create /dev/ttyprintk and not /dev/ttyprintk0.
+ * Applicable only when a driver for a single tty device is
+ * being allocated.
*/
#define TTY_DRIVER_INSTALLED 0x0001
#define TTY_DRIVER_RESET_TERMIOS 0x0002
@@ -387,6 +406,8 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
#define TTY_DRIVER_DYNAMIC_DEV 0x0008
#define TTY_DRIVER_DEVPTS_MEM 0x0010
#define TTY_DRIVER_HARDWARE_BREAK 0x0020
+#define TTY_DRIVER_DYNAMIC_ALLOC 0x0040
+#define TTY_DRIVER_UNNUMBERED_NODE 0x0080
/* tty driver types */
#define TTY_DRIVER_TYPE_SYSTEM 0x0001
diff --git a/include/linux/tty_flags.h b/include/linux/tty_flags.h
new file mode 100644
index 000000000000..eefcb483a2c0
--- /dev/null
+++ b/include/linux/tty_flags.h
@@ -0,0 +1,78 @@
+#ifndef _LINUX_TTY_FLAGS_H
+#define _LINUX_TTY_FLAGS_H
+
+/*
+ * Definitions for async_struct (and serial_struct) flags field also
+ * shared by the tty_port flags structures.
+ *
+ * Define ASYNCB_* for convenient use with {test,set,clear}_bit.
+ */
+#define ASYNCB_HUP_NOTIFY 0 /* Notify getty on hangups and closes
+ * on the callout port */
+#define ASYNCB_FOURPORT 1 /* Set OU1, OUT2 per AST Fourport settings */
+#define ASYNCB_SAK 2 /* Secure Attention Key (Orange book) */
+#define ASYNCB_SPLIT_TERMIOS 3 /* Separate termios for dialin/callout */
+#define ASYNCB_SPD_HI 4 /* Use 56000 instead of 38400 bps */
+#define ASYNCB_SPD_VHI 5 /* Use 115200 instead of 38400 bps */
+#define ASYNCB_SKIP_TEST 6 /* Skip UART test during autoconfiguration */
+#define ASYNCB_AUTO_IRQ 7 /* Do automatic IRQ during
+ * autoconfiguration */
+#define ASYNCB_SESSION_LOCKOUT 8 /* Lock out cua opens based on session */
+#define ASYNCB_PGRP_LOCKOUT 9 /* Lock out cua opens based on pgrp */
+#define ASYNCB_CALLOUT_NOHUP 10 /* Don't do hangups for cua device */
+#define ASYNCB_HARDPPS_CD 11 /* Call hardpps when CD goes high */
+#define ASYNCB_SPD_SHI 12 /* Use 230400 instead of 38400 bps */
+#define ASYNCB_LOW_LATENCY 13 /* Request low latency behaviour */
+#define ASYNCB_BUGGY_UART 14 /* This is a buggy UART, skip some safety
+ * checks. Note: can be dangerous! */
+#define ASYNCB_AUTOPROBE 15 /* Port was autoprobed by PCI or PNP code */
+#define ASYNCB_LAST_USER 15
+
+/* Internal flags used only by kernel */
+#define ASYNCB_INITIALIZED 31 /* Serial port was initialized */
+#define ASYNCB_SUSPENDED 30 /* Serial port is suspended */
+#define ASYNCB_NORMAL_ACTIVE 29 /* Normal device is active */
+#define ASYNCB_BOOT_AUTOCONF 28 /* Autoconfigure port on bootup */
+#define ASYNCB_CLOSING 27 /* Serial port is closing */
+#define ASYNCB_CTS_FLOW 26 /* Do CTS flow control */
+#define ASYNCB_CHECK_CD 25 /* i.e., CLOCAL */
+#define ASYNCB_SHARE_IRQ 24 /* for multifunction cards, no longer used */
+#define ASYNCB_CONS_FLOW 23 /* flow control for console */
+#define ASYNCB_FIRST_KERNEL 22
+
+#define ASYNC_HUP_NOTIFY (1U << ASYNCB_HUP_NOTIFY)
+#define ASYNC_SUSPENDED (1U << ASYNCB_SUSPENDED)
+#define ASYNC_FOURPORT (1U << ASYNCB_FOURPORT)
+#define ASYNC_SAK (1U << ASYNCB_SAK)
+#define ASYNC_SPLIT_TERMIOS (1U << ASYNCB_SPLIT_TERMIOS)
+#define ASYNC_SPD_HI (1U << ASYNCB_SPD_HI)
+#define ASYNC_SPD_VHI (1U << ASYNCB_SPD_VHI)
+#define ASYNC_SKIP_TEST (1U << ASYNCB_SKIP_TEST)
+#define ASYNC_AUTO_IRQ (1U << ASYNCB_AUTO_IRQ)
+#define ASYNC_SESSION_LOCKOUT (1U << ASYNCB_SESSION_LOCKOUT)
+#define ASYNC_PGRP_LOCKOUT (1U << ASYNCB_PGRP_LOCKOUT)
+#define ASYNC_CALLOUT_NOHUP (1U << ASYNCB_CALLOUT_NOHUP)
+#define ASYNC_HARDPPS_CD (1U << ASYNCB_HARDPPS_CD)
+#define ASYNC_SPD_SHI (1U << ASYNCB_SPD_SHI)
+#define ASYNC_LOW_LATENCY (1U << ASYNCB_LOW_LATENCY)
+#define ASYNC_BUGGY_UART (1U << ASYNCB_BUGGY_UART)
+#define ASYNC_AUTOPROBE (1U << ASYNCB_AUTOPROBE)
+
+#define ASYNC_FLAGS ((1U << (ASYNCB_LAST_USER + 1)) - 1)
+#define ASYNC_USR_MASK (ASYNC_SPD_MASK|ASYNC_CALLOUT_NOHUP| \
+ ASYNC_LOW_LATENCY)
+#define ASYNC_SPD_CUST (ASYNC_SPD_HI|ASYNC_SPD_VHI)
+#define ASYNC_SPD_WARP (ASYNC_SPD_HI|ASYNC_SPD_SHI)
+#define ASYNC_SPD_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI)
+
+#define ASYNC_INITIALIZED (1U << ASYNCB_INITIALIZED)
+#define ASYNC_NORMAL_ACTIVE (1U << ASYNCB_NORMAL_ACTIVE)
+#define ASYNC_BOOT_AUTOCONF (1U << ASYNCB_BOOT_AUTOCONF)
+#define ASYNC_CLOSING (1U << ASYNCB_CLOSING)
+#define ASYNC_CTS_FLOW (1U << ASYNCB_CTS_FLOW)
+#define ASYNC_CHECK_CD (1U << ASYNCB_CHECK_CD)
+#define ASYNC_SHARE_IRQ (1U << ASYNCB_SHARE_IRQ)
+#define ASYNC_CONS_FLOW (1U << ASYNCB_CONS_FLOW)
+#define ASYNC_INTERNAL_FLAGS (~((1U << ASYNCB_FIRST_KERNEL) - 1))
+
+#endif
diff --git a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h
index 59ba38bc400f..80ffde3bb164 100644
--- a/include/net/irda/ircomm_tty.h
+++ b/include/net/irda/ircomm_tty.h
@@ -52,21 +52,16 @@
/* Same for payload size. See qos.c for the smallest max data size */
#define IRCOMM_TTY_DATA_UNINITIALISED (64 - IRCOMM_TTY_HDR_UNINITIALISED)
-/* Those are really defined in include/linux/serial.h - Jean II */
-#define ASYNC_B_INITIALIZED 31 /* Serial port was initialized */
-#define ASYNC_B_NORMAL_ACTIVE 29 /* Normal device is active */
-#define ASYNC_B_CLOSING 27 /* Serial port is closing */
-
/*
* IrCOMM TTY driver state
*/
struct ircomm_tty_cb {
irda_queue_t queue; /* Must be first */
+ struct tty_port port;
magic_t magic;
int state; /* Connect state */
- struct tty_struct *tty;
struct ircomm_cb *ircomm; /* IrCOMM layer instance */
struct sk_buff *tx_skb; /* Transmit buffer */
@@ -80,7 +75,6 @@ struct ircomm_tty_cb {
LOCAL_FLOW flow; /* IrTTP flow status */
int line;
- unsigned long flags;
__u8 dlsap_sel;
__u8 slsap_sel;
@@ -97,19 +91,10 @@ struct ircomm_tty_cb {
void *skey;
void *ckey;
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
struct timer_list watchdog_timer;
struct work_struct tqueue;
- unsigned short close_delay;
- unsigned short closing_wait; /* time to wait before closing */
-
- int open_count;
- int blocked_open; /* # of blocked opens */
-
/* Protect concurent access to :
- * o self->open_count
* o self->ctrl_skb
* o self->tx_skb
* Maybe other things may gain to be protected as well...
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c
index 0557f24c6bca..17e073c309e6 100644
--- a/kernel/debug/debug_core.c
+++ b/kernel/debug/debug_core.c
@@ -672,6 +672,10 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs)
{
struct kgdb_state kgdb_var;
struct kgdb_state *ks = &kgdb_var;
+ int ret = 0;
+
+ if (arch_kgdb_ops.enable_nmi)
+ arch_kgdb_ops.enable_nmi(0);
ks->cpu = raw_smp_processor_id();
ks->ex_vector = evector;
@@ -681,11 +685,15 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs)
ks->linux_regs = regs;
if (kgdb_reenter_check(ks))
- return 0; /* Ouch, double exception ! */
+ goto out; /* Ouch, double exception ! */
if (kgdb_info[ks->cpu].enter_kgdb != 0)
- return 0;
+ goto out;
- return kgdb_cpu_enter(ks, regs, DCPU_WANT_MASTER);
+ ret = kgdb_cpu_enter(ks, regs, DCPU_WANT_MASTER);
+out:
+ if (arch_kgdb_ops.enable_nmi)
+ arch_kgdb_ops.enable_nmi(1);
+ return ret;
}
int kgdb_nmicallback(int cpu, void *regs)
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c
index 31df1706b9a9..1261dc7eaeb9 100644
--- a/kernel/debug/kdb/kdb_main.c
+++ b/kernel/debug/kdb/kdb_main.c
@@ -21,6 +21,7 @@
#include <linux/smp.h>
#include <linux/utsname.h>
#include <linux/vmalloc.h>
+#include <linux/atomic.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/init.h>
@@ -2107,6 +2108,32 @@ static int kdb_dmesg(int argc, const char **argv)
return 0;
}
#endif /* CONFIG_PRINTK */
+
+/* Make sure we balance enable/disable calls, must disable first. */
+static atomic_t kdb_nmi_disabled;
+
+static int kdb_disable_nmi(int argc, const char *argv[])
+{
+ if (atomic_read(&kdb_nmi_disabled))
+ return 0;
+ atomic_set(&kdb_nmi_disabled, 1);
+ arch_kgdb_ops.enable_nmi(0);
+ return 0;
+}
+
+static int kdb_param_enable_nmi(const char *val, const struct kernel_param *kp)
+{
+ if (!atomic_add_unless(&kdb_nmi_disabled, -1, 0))
+ return -EINVAL;
+ arch_kgdb_ops.enable_nmi(1);
+ return 0;
+}
+
+static const struct kernel_param_ops kdb_param_ops_enable_nmi = {
+ .set = kdb_param_enable_nmi,
+};
+module_param_cb(enable_nmi, &kdb_param_ops_enable_nmi, NULL, 0600);
+
/*
* kdb_cpu - This function implements the 'cpu' command.
* cpu [<cpunum>]
@@ -2851,6 +2878,10 @@ static void __init kdb_inittab(void)
kdb_register_repeat("dmesg", kdb_dmesg, "[lines]",
"Display syslog buffer", 0, KDB_REPEAT_NONE);
#endif
+ if (arch_kgdb_ops.enable_nmi) {
+ kdb_register_repeat("disable_nmi", kdb_disable_nmi, "",
+ "Disable NMI entry to KDB", 0, KDB_REPEAT_NONE);
+ }
kdb_register_repeat("defcmd", kdb_defcmd, "name \"usage\" \"help\"",
"Define a set of commands, down to endefcmd", 0, KDB_REPEAT_NONE);
kdb_register_repeat("kill", kdb_kill, "<-signal> <pid>",
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 56f182393c4c..ccc248791d50 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -278,8 +278,8 @@ out:
if (err < 0)
goto free;
- dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL);
-
+ dev->tty_dev = tty_port_register_device(&dev->port, rfcomm_tty_driver,
+ dev->id, NULL);
if (IS_ERR(dev->tty_dev)) {
err = PTR_ERR(dev->tty_dev);
list_del(&dev->list);
@@ -705,9 +705,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
break;
}
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->wait, &wait);
@@ -861,7 +861,7 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned l
static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
{
- struct ktermios *new = tty->termios;
+ struct ktermios *new = &tty->termios;
int old_baud_rate = tty_termios_baud_rate(old);
int new_baud_rate = tty_termios_baud_rate(new);
diff --git a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c
index 8b915f3ac3b9..308939128359 100644
--- a/net/irda/ircomm/ircomm_param.c
+++ b/net/irda/ircomm/ircomm_param.c
@@ -99,7 +99,6 @@ pi_param_info_t ircomm_param_info = { pi_major_call_table, 3, 0x0f, 4 };
*/
int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
{
- struct tty_struct *tty;
unsigned long flags;
struct sk_buff *skb;
int count;
@@ -109,10 +108,6 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
- tty = self->tty;
- if (!tty)
- return 0;
-
/* Make sure we don't send parameters for raw mode */
if (self->service_type == IRCOMM_3_WIRE_RAW)
return 0;
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index 6b9d5a0e42f9..95a3a7a336ba 100644
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -52,6 +52,8 @@
#include <net/irda/ircomm_tty_attach.h>
#include <net/irda/ircomm_tty.h>
+static int ircomm_tty_install(struct tty_driver *driver,
+ struct tty_struct *tty);
static int ircomm_tty_open(struct tty_struct *tty, struct file *filp);
static void ircomm_tty_close(struct tty_struct * tty, struct file *filp);
static int ircomm_tty_write(struct tty_struct * tty,
@@ -82,6 +84,7 @@ static struct tty_driver *driver;
static hashbin_t *ircomm_tty = NULL;
static const struct tty_operations ops = {
+ .install = ircomm_tty_install,
.open = ircomm_tty_open,
.close = ircomm_tty_close,
.write = ircomm_tty_write,
@@ -104,6 +107,35 @@ static const struct tty_operations ops = {
#endif /* CONFIG_PROC_FS */
};
+static void ircomm_port_raise_dtr_rts(struct tty_port *port, int raise)
+{
+ struct ircomm_tty_cb *self = container_of(port, struct ircomm_tty_cb,
+ port);
+ /*
+ * Here, we use to lock those two guys, but as ircomm_param_request()
+ * does it itself, I don't see the point (and I see the deadlock).
+ * Jean II
+ */
+ if (raise)
+ self->settings.dte |= IRCOMM_RTS | IRCOMM_DTR;
+ else
+ self->settings.dte &= ~(IRCOMM_RTS | IRCOMM_DTR);
+
+ ircomm_param_request(self, IRCOMM_DTE, TRUE);
+}
+
+static int ircomm_port_carrier_raised(struct tty_port *port)
+{
+ struct ircomm_tty_cb *self = container_of(port, struct ircomm_tty_cb,
+ port);
+ return self->settings.dce & IRCOMM_CD;
+}
+
+static const struct tty_port_operations ircomm_port_ops = {
+ .dtr_rts = ircomm_port_raise_dtr_rts,
+ .carrier_raised = ircomm_port_carrier_raised,
+};
+
/*
* Function ircomm_tty_init()
*
@@ -194,7 +226,7 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self)
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
/* Check if already open */
- if (test_and_set_bit(ASYNC_B_INITIALIZED, &self->flags)) {
+ if (test_and_set_bit(ASYNCB_INITIALIZED, &self->port.flags)) {
IRDA_DEBUG(2, "%s(), already open so break out!\n", __func__ );
return 0;
}
@@ -231,7 +263,7 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self)
return 0;
err:
- clear_bit(ASYNC_B_INITIALIZED, &self->flags);
+ clear_bit(ASYNCB_INITIALIZED, &self->port.flags);
return ret;
}
@@ -242,72 +274,62 @@ err:
*
*/
static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
- struct file *filp)
+ struct tty_struct *tty, struct file *filp)
{
+ struct tty_port *port = &self->port;
DECLARE_WAITQUEUE(wait, current);
int retval;
int do_clocal = 0, extra_count = 0;
unsigned long flags;
- struct tty_struct *tty;
IRDA_DEBUG(2, "%s()\n", __func__ );
- tty = self->tty;
-
/*
* If non-blocking mode is set, or the port is not enabled,
* then make the check up front and then exit.
*/
if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
/* nonblock mode is set or port is not enabled */
- self->flags |= ASYNC_NORMAL_ACTIVE;
+ port->flags |= ASYNC_NORMAL_ACTIVE;
IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __func__ );
return 0;
}
- if (tty->termios->c_cflag & CLOCAL) {
+ if (tty->termios.c_cflag & CLOCAL) {
IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __func__ );
do_clocal = 1;
}
/* Wait for carrier detect and the line to become
* free (i.e., not in use by the callout). While we are in
- * this loop, self->open_count is dropped by one, so that
+ * this loop, port->count is dropped by one, so that
* mgsl_close() knows when to free things. We restore it upon
* exit, either normal or abnormal.
*/
retval = 0;
- add_wait_queue(&self->open_wait, &wait);
+ add_wait_queue(&port->open_wait, &wait);
IRDA_DEBUG(2, "%s(%d):block_til_ready before block on %s open_count=%d\n",
- __FILE__,__LINE__, tty->driver->name, self->open_count );
+ __FILE__, __LINE__, tty->driver->name, port->count);
- /* As far as I can see, we protect open_count - Jean II */
- spin_lock_irqsave(&self->spinlock, flags);
+ spin_lock_irqsave(&port->lock, flags);
if (!tty_hung_up_p(filp)) {
extra_count = 1;
- self->open_count--;
+ port->count--;
}
- spin_unlock_irqrestore(&self->spinlock, flags);
- self->blocked_open++;
+ spin_unlock_irqrestore(&port->lock, flags);
+ port->blocked_open++;
while (1) {
- if (tty->termios->c_cflag & CBAUD) {
- /* Here, we use to lock those two guys, but
- * as ircomm_param_request() does it itself,
- * I don't see the point (and I see the deadlock).
- * Jean II */
- self->settings.dte |= IRCOMM_RTS + IRCOMM_DTR;
-
- ircomm_param_request(self, IRCOMM_DTE, TRUE);
- }
+ if (tty->termios.c_cflag & CBAUD)
+ tty_port_raise_dtr_rts(port);
current->state = TASK_INTERRUPTIBLE;
if (tty_hung_up_p(filp) ||
- !test_bit(ASYNC_B_INITIALIZED, &self->flags)) {
- retval = (self->flags & ASYNC_HUP_NOTIFY) ?
+ !test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+ retval = (port->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS;
break;
}
@@ -317,8 +339,8 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
* specified, we cannot return before the IrCOMM link is
* ready
*/
- if (!test_bit(ASYNC_B_CLOSING, &self->flags) &&
- (do_clocal || (self->settings.dce & IRCOMM_CD)) &&
+ if (!test_bit(ASYNCB_CLOSING, &port->flags) &&
+ (do_clocal || tty_port_carrier_raised(port)) &&
self->state == IRCOMM_TTY_READY)
{
break;
@@ -330,46 +352,36 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
}
IRDA_DEBUG(1, "%s(%d):block_til_ready blocking on %s open_count=%d\n",
- __FILE__,__LINE__, tty->driver->name, self->open_count );
+ __FILE__, __LINE__, tty->driver->name, port->count);
schedule();
}
__set_current_state(TASK_RUNNING);
- remove_wait_queue(&self->open_wait, &wait);
+ remove_wait_queue(&port->open_wait, &wait);
if (extra_count) {
/* ++ is not atomic, so this should be protected - Jean II */
- spin_lock_irqsave(&self->spinlock, flags);
- self->open_count++;
- spin_unlock_irqrestore(&self->spinlock, flags);
+ spin_lock_irqsave(&port->lock, flags);
+ port->count++;
+ spin_unlock_irqrestore(&port->lock, flags);
}
- self->blocked_open--;
+ port->blocked_open--;
IRDA_DEBUG(1, "%s(%d):block_til_ready after blocking on %s open_count=%d\n",
- __FILE__,__LINE__, tty->driver->name, self->open_count);
+ __FILE__, __LINE__, tty->driver->name, port->count);
if (!retval)
- self->flags |= ASYNC_NORMAL_ACTIVE;
+ port->flags |= ASYNC_NORMAL_ACTIVE;
return retval;
}
-/*
- * Function ircomm_tty_open (tty, filp)
- *
- * This routine is called when a particular tty device is opened. This
- * routine is mandatory; if this routine is not filled in, the attempted
- * open will fail with ENODEV.
- */
-static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
+
+static int ircomm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct ircomm_tty_cb *self;
unsigned int line = tty->index;
- unsigned long flags;
- int ret;
-
- IRDA_DEBUG(2, "%s()\n", __func__ );
/* Check if instance already exists */
self = hashbin_lock_find(ircomm_tty, line, NULL);
@@ -381,6 +393,8 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
return -ENOMEM;
}
+ tty_port_init(&self->port);
+ self->port.ops = &ircomm_port_ops;
self->magic = IRCOMM_TTY_MAGIC;
self->flow = FLOW_STOP;
@@ -388,13 +402,9 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
INIT_WORK(&self->tqueue, ircomm_tty_do_softint);
self->max_header_size = IRCOMM_TTY_HDR_UNINITIALISED;
self->max_data_size = IRCOMM_TTY_DATA_UNINITIALISED;
- self->close_delay = 5*HZ/10;
- self->closing_wait = 30*HZ;
/* Init some important stuff */
init_timer(&self->watchdog_timer);
- init_waitqueue_head(&self->open_wait);
- init_waitqueue_head(&self->close_wait);
spin_lock_init(&self->spinlock);
/*
@@ -404,31 +414,48 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
*
* Note this is completely usafe and doesn't work properly
*/
- tty->termios->c_iflag = 0;
- tty->termios->c_oflag = 0;
+ tty->termios.c_iflag = 0;
+ tty->termios.c_oflag = 0;
/* Insert into hash */
hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL);
}
- /* ++ is not atomic, so this should be protected - Jean II */
- spin_lock_irqsave(&self->spinlock, flags);
- self->open_count++;
- tty->driver_data = self;
- self->tty = tty;
- spin_unlock_irqrestore(&self->spinlock, flags);
+ return tty_port_install(&self->port, driver, tty);
+}
+
+/*
+ * Function ircomm_tty_open (tty, filp)
+ *
+ * This routine is called when a particular tty device is opened. This
+ * routine is mandatory; if this routine is not filled in, the attempted
+ * open will fail with ENODEV.
+ */
+static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
+{
+ struct ircomm_tty_cb *self = tty->driver_data;
+ unsigned long flags;
+ int ret;
+
+ IRDA_DEBUG(2, "%s()\n", __func__ );
+
+ /* ++ is not atomic, so this should be protected - Jean II */
+ spin_lock_irqsave(&self->port.lock, flags);
+ self->port.count++;
+ spin_unlock_irqrestore(&self->port.lock, flags);
+ tty_port_tty_set(&self->port, tty);
IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __func__ , tty->driver->name,
- self->line, self->open_count);
+ self->line, self->port.count);
/* Not really used by us, but lets do it anyway */
- self->tty->low_latency = (self->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ tty->low_latency = (self->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
/*
* If the port is the middle of closing, bail out now
*/
if (tty_hung_up_p(filp) ||
- test_bit(ASYNC_B_CLOSING, &self->flags)) {
+ test_bit(ASYNCB_CLOSING, &self->port.flags)) {
/* Hm, why are we blocking on ASYNC_CLOSING if we
* do return -EAGAIN/-ERESTARTSYS below anyway?
@@ -438,14 +465,15 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
* probably better sleep uninterruptible?
*/
- if (wait_event_interruptible(self->close_wait, !test_bit(ASYNC_B_CLOSING, &self->flags))) {
+ if (wait_event_interruptible(self->port.close_wait,
+ !test_bit(ASYNCB_CLOSING, &self->port.flags))) {
IRDA_WARNING("%s - got signal while blocking on ASYNC_CLOSING!\n",
__func__);
return -ERESTARTSYS;
}
#ifdef SERIAL_DO_RESTART
- return (self->flags & ASYNC_HUP_NOTIFY) ?
+ return (self->port.flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS;
#else
return -EAGAIN;
@@ -453,7 +481,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
}
/* Check if this is a "normal" ircomm device, or an irlpt device */
- if (line < 0x10) {
+ if (self->line < 0x10) {
self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;
self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */
/* Jan Kiszka -> add DSR/RI -> Conform to IrCOMM spec */
@@ -469,7 +497,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
if (ret)
return ret;
- ret = ircomm_tty_block_til_ready(self, filp);
+ ret = ircomm_tty_block_til_ready(self, tty, filp);
if (ret) {
IRDA_DEBUG(2,
"%s(), returning after block_til_ready with %d\n", __func__ ,
@@ -489,81 +517,22 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- unsigned long flags;
+ struct tty_port *port = &self->port;
IRDA_DEBUG(0, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
- spin_lock_irqsave(&self->spinlock, flags);
-
- if (tty_hung_up_p(filp)) {
- spin_unlock_irqrestore(&self->spinlock, flags);
-
- IRDA_DEBUG(0, "%s(), returning 1\n", __func__ );
- return;
- }
-
- if ((tty->count == 1) && (self->open_count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. state->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- IRDA_DEBUG(0, "%s(), bad serial port count; "
- "tty->count is 1, state->count is %d\n", __func__ ,
- self->open_count);
- self->open_count = 1;
- }
-
- if (--self->open_count < 0) {
- IRDA_ERROR("%s(), bad serial port count for ttys%d: %d\n",
- __func__, self->line, self->open_count);
- self->open_count = 0;
- }
- if (self->open_count) {
- spin_unlock_irqrestore(&self->spinlock, flags);
-
- IRDA_DEBUG(0, "%s(), open count > 0\n", __func__ );
+ if (tty_port_close_start(port, tty, filp) == 0)
return;
- }
-
- /* Hum... Should be test_and_set_bit ??? - Jean II */
- set_bit(ASYNC_B_CLOSING, &self->flags);
-
- /* We need to unlock here (we were unlocking at the end of this
- * function), because tty_wait_until_sent() may schedule.
- * I don't know if the rest should be protected somehow,
- * so someone should check. - Jean II */
- spin_unlock_irqrestore(&self->spinlock, flags);
-
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- if (self->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- tty_wait_until_sent_from_close(tty, self->closing_wait);
ircomm_tty_shutdown(self);
tty_driver_flush_buffer(tty);
- tty_ldisc_flush(tty);
-
- tty->closing = 0;
- self->tty = NULL;
- if (self->blocked_open) {
- if (self->close_delay)
- schedule_timeout_interruptible(self->close_delay);
- wake_up_interruptible(&self->open_wait);
- }
-
- self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
- wake_up_interruptible(&self->close_wait);
+ tty_port_close_end(port, tty);
+ tty_port_tty_set(port, NULL);
}
/*
@@ -606,7 +575,7 @@ static void ircomm_tty_do_softint(struct work_struct *work)
if (!self || self->magic != IRCOMM_TTY_MAGIC)
return;
- tty = self->tty;
+ tty = tty_port_tty_get(&self->port);
if (!tty)
return;
@@ -627,7 +596,7 @@ static void ircomm_tty_do_softint(struct work_struct *work)
}
if (tty->hw_stopped)
- return;
+ goto put;
/* Unlink transmit buffer */
spin_lock_irqsave(&self->spinlock, flags);
@@ -646,6 +615,8 @@ static void ircomm_tty_do_softint(struct work_struct *work)
/* Check if user (still) wants to be waken up */
tty_wakeup(tty);
+put:
+ tty_kref_put(tty);
}
/*
@@ -880,7 +851,7 @@ static void ircomm_tty_throttle(struct tty_struct *tty)
ircomm_tty_send_xchar(tty, STOP_CHAR(tty));
/* Hardware flow control? */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
self->settings.dte &= ~IRCOMM_RTS;
self->settings.dte |= IRCOMM_DELTA_RTS;
@@ -912,7 +883,7 @@ static void ircomm_tty_unthrottle(struct tty_struct *tty)
}
/* Using hardware flow control? */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS);
ircomm_param_request(self, IRCOMM_DTE, TRUE);
@@ -955,7 +926,7 @@ static void ircomm_tty_shutdown(struct ircomm_tty_cb *self)
IRDA_DEBUG(0, "%s()\n", __func__ );
- if (!test_and_clear_bit(ASYNC_B_INITIALIZED, &self->flags))
+ if (!test_and_clear_bit(ASYNCB_INITIALIZED, &self->port.flags))
return;
ircomm_tty_detach_cable(self);
@@ -994,6 +965,7 @@ static void ircomm_tty_shutdown(struct ircomm_tty_cb *self)
static void ircomm_tty_hangup(struct tty_struct *tty)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+ struct tty_port *port = &self->port;
unsigned long flags;
IRDA_DEBUG(0, "%s()\n", __func__ );
@@ -1004,14 +976,17 @@ static void ircomm_tty_hangup(struct tty_struct *tty)
/* ircomm_tty_flush_buffer(tty); */
ircomm_tty_shutdown(self);
- /* I guess we need to lock here - Jean II */
- spin_lock_irqsave(&self->spinlock, flags);
- self->flags &= ~ASYNC_NORMAL_ACTIVE;
- self->tty = NULL;
- self->open_count = 0;
- spin_unlock_irqrestore(&self->spinlock, flags);
+ spin_lock_irqsave(&port->lock, flags);
+ port->flags &= ~ASYNC_NORMAL_ACTIVE;
+ if (port->tty) {
+ set_bit(TTY_IO_ERROR, &port->tty->flags);
+ tty_kref_put(port->tty);
+ }
+ port->tty = NULL;
+ port->count = 0;
+ spin_unlock_irqrestore(&port->lock, flags);
- wake_up_interruptible(&self->open_wait);
+ wake_up_interruptible(&port->open_wait);
}
/*
@@ -1071,20 +1046,20 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
- tty = self->tty;
+ tty = tty_port_tty_get(&self->port);
status = self->settings.dce;
if (status & IRCOMM_DCE_DELTA_ANY) {
/*wake_up_interruptible(&self->delta_msr_wait);*/
}
- if ((self->flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) {
+ if ((self->port.flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) {
IRDA_DEBUG(2,
"%s(), ircomm%d CD now %s...\n", __func__ , self->line,
(status & IRCOMM_CD) ? "on" : "off");
if (status & IRCOMM_CD) {
- wake_up_interruptible(&self->open_wait);
+ wake_up_interruptible(&self->port.open_wait);
} else {
IRDA_DEBUG(2,
"%s(), Doing serial hangup..\n", __func__ );
@@ -1092,10 +1067,10 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
tty_hangup(tty);
/* Hangup will remote the tty, so better break out */
- return;
+ goto put;
}
}
- if (self->flags & ASYNC_CTS_FLOW) {
+ if (tty && tty_port_cts_enabled(&self->port)) {
if (tty->hw_stopped) {
if (status & IRCOMM_CTS) {
IRDA_DEBUG(2,
@@ -1103,10 +1078,10 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
tty->hw_stopped = 0;
/* Wake up processes blocked on open */
- wake_up_interruptible(&self->open_wait);
+ wake_up_interruptible(&self->port.open_wait);
schedule_work(&self->tqueue);
- return;
+ goto put;
}
} else {
if (!(status & IRCOMM_CTS)) {
@@ -1116,6 +1091,8 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
}
}
}
+put:
+ tty_kref_put(tty);
}
/*
@@ -1128,6 +1105,7 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
struct sk_buff *skb)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+ struct tty_struct *tty;
IRDA_DEBUG(2, "%s()\n", __func__ );
@@ -1135,7 +1113,8 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
IRDA_ASSERT(skb != NULL, return -1;);
- if (!self->tty) {
+ tty = tty_port_tty_get(&self->port);
+ if (!tty) {
IRDA_DEBUG(0, "%s(), no tty!\n", __func__ );
return 0;
}
@@ -1146,7 +1125,7 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
* Devices like WinCE can do this, and since they don't send any
* params, we can just as well declare the hardware for running.
*/
- if (self->tty->hw_stopped && (self->flow == FLOW_START)) {
+ if (tty->hw_stopped && (self->flow == FLOW_START)) {
IRDA_DEBUG(0, "%s(), polling for line settings!\n", __func__ );
ircomm_param_request(self, IRCOMM_POLL, TRUE);
@@ -1159,8 +1138,9 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
* Use flip buffer functions since the code may be called from interrupt
* context
*/
- tty_insert_flip_string(self->tty, skb->data, skb->len);
- tty_flip_buffer_push(self->tty);
+ tty_insert_flip_string(tty, skb->data, skb->len);
+ tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
/* No need to kfree_skb - see ircomm_ttp_data_indication() */
@@ -1211,12 +1191,13 @@ static void ircomm_tty_flow_indication(void *instance, void *sap,
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
- tty = self->tty;
+ tty = tty_port_tty_get(&self->port);
switch (cmd) {
case FLOW_START:
IRDA_DEBUG(2, "%s(), hw start!\n", __func__ );
- tty->hw_stopped = 0;
+ if (tty)
+ tty->hw_stopped = 0;
/* ircomm_tty_do_softint will take care of the rest */
schedule_work(&self->tqueue);
@@ -1224,15 +1205,19 @@ static void ircomm_tty_flow_indication(void *instance, void *sap,
default: /* If we get here, something is very wrong, better stop */
case FLOW_STOP:
IRDA_DEBUG(2, "%s(), hw stopped!\n", __func__ );
- tty->hw_stopped = 1;
+ if (tty)
+ tty->hw_stopped = 1;
break;
}
+
+ tty_kref_put(tty);
self->flow = cmd;
}
#ifdef CONFIG_PROC_FS
static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m)
{
+ struct tty_struct *tty;
char sep;
seq_printf(m, "State: %s\n", ircomm_tty_state[self->state]);
@@ -1328,40 +1313,43 @@ static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m)
seq_puts(m, "Flags:");
sep = ' ';
- if (self->flags & ASYNC_CTS_FLOW) {
+ if (tty_port_cts_enabled(&self->port)) {
seq_printf(m, "%cASYNC_CTS_FLOW", sep);
sep = '|';
}
- if (self->flags & ASYNC_CHECK_CD) {
+ if (self->port.flags & ASYNC_CHECK_CD) {
seq_printf(m, "%cASYNC_CHECK_CD", sep);
sep = '|';
}
- if (self->flags & ASYNC_INITIALIZED) {
+ if (self->port.flags & ASYNC_INITIALIZED) {
seq_printf(m, "%cASYNC_INITIALIZED", sep);
sep = '|';
}
- if (self->flags & ASYNC_LOW_LATENCY) {
+ if (self->port.flags & ASYNC_LOW_LATENCY) {
seq_printf(m, "%cASYNC_LOW_LATENCY", sep);
sep = '|';
}
- if (self->flags & ASYNC_CLOSING) {
+ if (self->port.flags & ASYNC_CLOSING) {
seq_printf(m, "%cASYNC_CLOSING", sep);
sep = '|';
}
- if (self->flags & ASYNC_NORMAL_ACTIVE) {
+ if (self->port.flags & ASYNC_NORMAL_ACTIVE) {
seq_printf(m, "%cASYNC_NORMAL_ACTIVE", sep);
sep = '|';
}
seq_putc(m, '\n');
seq_printf(m, "Role: %s\n", self->client ? "client" : "server");
- seq_printf(m, "Open count: %d\n", self->open_count);
+ seq_printf(m, "Open count: %d\n", self->port.count);
seq_printf(m, "Max data size: %d\n", self->max_data_size);
seq_printf(m, "Max header size: %d\n", self->max_header_size);
- if (self->tty)
+ tty = tty_port_tty_get(&self->port);
+ if (tty) {
seq_printf(m, "Hardware: %s\n",
- self->tty->hw_stopped ? "Stopped" : "Running");
+ tty->hw_stopped ? "Stopped" : "Running");
+ tty_kref_put(tty);
+ }
}
static int ircomm_tty_proc_show(struct seq_file *m, void *v)
diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c
index b65d66e0d817..edab393e0c82 100644
--- a/net/irda/ircomm/ircomm_tty_attach.c
+++ b/net/irda/ircomm/ircomm_tty_attach.c
@@ -130,6 +130,8 @@ static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
*/
int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
{
+ struct tty_struct *tty;
+
IRDA_DEBUG(0, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return -1;);
@@ -142,7 +144,11 @@ int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
}
/* Make sure nobody tries to write before the link is up */
- self->tty->hw_stopped = 1;
+ tty = tty_port_tty_get(&self->port);
+ if (tty) {
+ tty->hw_stopped = 1;
+ tty_kref_put(tty);
+ }
ircomm_tty_ias_register(self);
@@ -398,23 +404,26 @@ void ircomm_tty_disconnect_indication(void *instance, void *sap,
struct sk_buff *skb)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+ struct tty_struct *tty;
IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
- if (!self->tty)
+ tty = tty_port_tty_get(&self->port);
+ if (!tty)
return;
/* This will stop control data transfers */
self->flow = FLOW_STOP;
/* Stop data transfers */
- self->tty->hw_stopped = 1;
+ tty->hw_stopped = 1;
ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL,
NULL);
+ tty_kref_put(tty);
}
/*
@@ -550,12 +559,15 @@ void ircomm_tty_connect_indication(void *instance, void *sap,
*/
void ircomm_tty_link_established(struct ircomm_tty_cb *self)
{
+ struct tty_struct *tty;
+
IRDA_DEBUG(2, "%s()\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
- if (!self->tty)
+ tty = tty_port_tty_get(&self->port);
+ if (!tty)
return;
del_timer(&self->watchdog_timer);
@@ -566,19 +578,22 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self)
* will have to wait for the peer device (DCE) to raise the CTS
* line.
*/
- if ((self->flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) {
+ if (tty_port_cts_enabled(&self->port) &&
+ ((self->settings.dce & IRCOMM_CTS) == 0)) {
IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __func__ );
- return;
+ goto put;
} else {
IRDA_DEBUG(1, "%s(), starting hardware!\n", __func__ );
- self->tty->hw_stopped = 0;
+ tty->hw_stopped = 0;
/* Wake up processes blocked on open */
- wake_up_interruptible(&self->open_wait);
+ wake_up_interruptible(&self->port.open_wait);
}
schedule_work(&self->tqueue);
+put:
+ tty_kref_put(tty);
}
/*
@@ -977,14 +992,17 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
ircomm_tty_start_watchdog_timer(self, 3*HZ);
- if (self->flags & ASYNC_CHECK_CD) {
+ if (self->port.flags & ASYNC_CHECK_CD) {
/* Drop carrier */
self->settings.dce = IRCOMM_DELTA_CD;
ircomm_tty_check_modem_status(self);
} else {
+ struct tty_struct *tty = tty_port_tty_get(&self->port);
IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ );
- if (self->tty)
- tty_hangup(self->tty);
+ if (tty) {
+ tty_hangup(tty);
+ tty_kref_put(tty);
+ }
}
break;
default:
diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c
index d0667d68351d..b343f50dc8d7 100644
--- a/net/irda/ircomm/ircomm_tty_ioctl.c
+++ b/net/irda/ircomm/ircomm_tty_ioctl.c
@@ -52,17 +52,18 @@
* Change speed of the driver. If the remote device is a DCE, then this
* should make it change the speed of its serial port
*/
-static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
+static void ircomm_tty_change_speed(struct ircomm_tty_cb *self,
+ struct tty_struct *tty)
{
unsigned int cflag, cval;
int baud;
IRDA_DEBUG(2, "%s()\n", __func__ );
- if (!self->tty || !self->tty->termios || !self->ircomm)
+ if (!self->ircomm)
return;
- cflag = self->tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
/* byte size and parity */
switch (cflag & CSIZE) {
@@ -81,7 +82,7 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
cval |= IRCOMM_PARITY_EVEN;
/* Determine divisor based on baud rate */
- baud = tty_get_baud_rate(self->tty);
+ baud = tty_get_baud_rate(tty);
if (!baud)
baud = 9600; /* B0 transition handled in rs_set_termios */
@@ -90,19 +91,19 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
/* CTS flow control flag and modem status interrupts */
if (cflag & CRTSCTS) {
- self->flags |= ASYNC_CTS_FLOW;
+ self->port.flags |= ASYNC_CTS_FLOW;
self->settings.flow_control |= IRCOMM_RTS_CTS_IN;
/* This got me. Bummer. Jean II */
if (self->service_type == IRCOMM_3_WIRE_RAW)
IRDA_WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __func__);
} else {
- self->flags &= ~ASYNC_CTS_FLOW;
+ self->port.flags &= ~ASYNC_CTS_FLOW;
self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
}
if (cflag & CLOCAL)
- self->flags &= ~ASYNC_CHECK_CD;
+ self->port.flags &= ~ASYNC_CHECK_CD;
else
- self->flags |= ASYNC_CHECK_CD;
+ self->port.flags |= ASYNC_CHECK_CD;
#if 0
/*
* Set up parity check flag
@@ -148,18 +149,18 @@ void ircomm_tty_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = tty->termios.c_cflag;
IRDA_DEBUG(2, "%s()\n", __func__ );
if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(tty->termios->c_iflag) ==
+ (RELEVANT_IFLAG(tty->termios.c_iflag) ==
RELEVANT_IFLAG(old_termios->c_iflag)))
{
return;
}
- ircomm_tty_change_speed(self);
+ ircomm_tty_change_speed(self, tty);
/* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) &&
@@ -172,7 +173,7 @@ void ircomm_tty_set_termios(struct tty_struct *tty,
if (!(old_termios->c_cflag & CBAUD) &&
(cflag & CBAUD)) {
self->settings.dte |= IRCOMM_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
+ if (!(tty->termios.c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
self->settings.dte |= IRCOMM_RTS;
}
@@ -181,7 +182,7 @@ void ircomm_tty_set_termios(struct tty_struct *tty,
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS))
+ !(tty->termios.c_cflag & CRTSCTS))
{
tty->hw_stopped = 0;
ircomm_tty_start(tty);
@@ -270,10 +271,10 @@ static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self,
memset(&info, 0, sizeof(info));
info.line = self->line;
- info.flags = self->flags;
+ info.flags = self->port.flags;
info.baud_base = self->settings.data_rate;
- info.close_delay = self->close_delay;
- info.closing_wait = self->closing_wait;
+ info.close_delay = self->port.close_delay;
+ info.closing_wait = self->port.closing_wait;
/* For compatibility */
info.type = PORT_16550A;