summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2009-06-30 14:45:43 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2009-06-30 14:45:43 +1000
commit5a87849dfc6543080716d3da3bb49babcebb8cfd (patch)
treea0f6ddf87dcb3624d2e95ea2efaa4d414cb4d17b
parent451edae46a155e091045cde24809d163592ec0aa (diff)
parent2db8616a214f9af0769720a3860b9bc4ac8c83c8 (diff)
Merge branch 'quilt/ttydev'
Conflicts: drivers/char/tty_ldisc.c
-rw-r--r--arch/x86/include/asm/termios.h25
-rw-r--r--drivers/char/cyclades.c2276
-rw-r--r--drivers/firmware/dmi_scan.c34
-rw-r--r--drivers/net/slip.c96
-rw-r--r--drivers/serial/8250.c22
-rw-r--r--drivers/serial/8250.h1
-rw-r--r--include/linux/cyclades.h10
-rw-r--r--include/linux/kfifo.h4
-rw-r--r--include/linux/serial_8250.h1
-rw-r--r--include/linux/serial_core.h1
-rw-r--r--kernel/kfifo.c2
11 files changed, 650 insertions, 1822 deletions
diff --git a/arch/x86/include/asm/termios.h b/arch/x86/include/asm/termios.h
index c4ee8056baca..ee6f0c859244 100644
--- a/arch/x86/include/asm/termios.h
+++ b/arch/x86/include/asm/termios.h
@@ -5,20 +5,20 @@
#include <asm/ioctls.h>
struct winsize {
- unsigned short ws_row;
- unsigned short ws_col;
- unsigned short ws_xpixel;
- unsigned short ws_ypixel;
+ unsigned short ws_row;
+ unsigned short ws_col;
+ unsigned short ws_xpixel;
+ unsigned short ws_ypixel;
};
#define NCC 8
struct termio {
- unsigned short c_iflag; /* input mode flags */
- unsigned short c_oflag; /* output mode flags */
- unsigned short c_cflag; /* control mode flags */
- unsigned short c_lflag; /* local mode flags */
- unsigned char c_line; /* line discipline */
- unsigned char c_cc[NCC]; /* control characters */
+ unsigned short c_iflag; /* input mode flags */
+ unsigned short c_oflag; /* output mode flags */
+ unsigned short c_cflag; /* control mode flags */
+ unsigned short c_lflag; /* local mode flags */
+ unsigned char c_line; /* line discipline */
+ unsigned char c_cc[NCC]; /* control characters */
};
/* modem lines */
@@ -37,10 +37,10 @@ struct termio {
#define TIOCM_OUT2 0x4000
#define TIOCM_LOOP 0x8000
-/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
-
#ifdef __KERNEL__
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
#include <asm/uaccess.h>
/* intr=^C quit=^\ erase=del kill=^U
@@ -110,5 +110,4 @@ static inline int kernel_termios_to_user_termios_1(struct termios __user *u,
}
#endif /* __KERNEL__ */
-
#endif /* _ASM_X86_TERMIOS_H */
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index f3366d3f06cf..dbfa8b50a5e8 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -11,7 +11,7 @@
* Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
* Modified and maintained by Marcio Saito <marcio@cyclades.com>.
*
- * Copyright (C) 2007 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (C) 2007-2009 Jiri Slaby <jirislaby@gmail.com>
*
* Much of the design and some of the code came from serial.c
* which was copyright (C) 1991, 1992 Linus Torvalds. It was
@@ -19,577 +19,9 @@
* and then fixed as suggested by Michael K. Johnson 12/12/92.
* Converted to pci probing and cleaned up by Jiri Slaby.
*
- * This version supports shared IRQ's (only for PCI boards).
- *
- * Prevent users from opening non-existing Z ports.
- *
- * Revision 2.3.2.8 2000/07/06 18:14:16 ivan
- * Fixed the PCI detection function to work properly on Alpha systems.
- * Implemented support for TIOCSERGETLSR ioctl.
- * Implemented full support for non-standard baud rates.
- *
- * Revision 2.3.2.7 2000/06/01 18:26:34 ivan
- * Request PLX I/O region, although driver doesn't use it, to avoid
- * problems with other drivers accessing it.
- * Removed count for on-board buffer characters in cy_chars_in_buffer
- * (Cyclades-Z only).
- *
- * Revision 2.3.2.6 2000/05/05 13:56:05 ivan
- * Driver now reports physical instead of virtual memory addresses.
- * Masks were added to some Cyclades-Z read accesses.
- * Implemented workaround for PLX9050 bug that would cause a system lockup
- * in certain systems, depending on the MMIO addresses allocated to the
- * board.
- * Changed the Tx interrupt programming in the CD1400 chips to boost up
- * performance (Cyclom-Y only).
- * Code is now compliant with the new module interface (module_[init|exit]).
- * Make use of the PCI helper functions to access PCI resources.
- * Did some code "housekeeping".
- *
- * Revision 2.3.2.5 2000/01/19 14:35:33 ivan
- * Fixed bug in cy_set_termios on CRTSCTS flag turnoff.
- *
- * Revision 2.3.2.4 2000/01/17 09:19:40 ivan
- * Fixed SMP locking in Cyclom-Y interrupt handler.
- *
- * Revision 2.3.2.3 1999/12/28 12:11:39 ivan
- * Added a new cyclades_card field called nports to allow the driver to
- * know the exact number of ports found by the Z firmware after its load;
- * RX buffer contention prevention logic on interrupt op mode revisited
- * (Cyclades-Z only);
- * Revisited printk's for Z debug;
- * Driver now makes sure that the constant SERIAL_XMIT_SIZE is defined;
- *
- * Revision 2.3.2.2 1999/10/01 11:27:43 ivan
- * Fixed bug in cyz_poll that would make all ports but port 0
- * unable to transmit/receive data (Cyclades-Z only);
- * Implemented logic to prevent the RX buffer from being stuck with data
- * due to a driver / firmware race condition in interrupt op mode
- * (Cyclades-Z only);
- * Fixed bug in block_til_ready logic that would lead to a system crash;
- * Revisited cy_close spinlock usage;
- *
- * Revision 2.3.2.1 1999/09/28 11:01:22 ivan
- * Revisited CONFIG_PCI conditional compilation for PCI board support;
- * Implemented TIOCGICOUNT and TIOCMIWAIT ioctl support;
- * _Major_ cleanup on the Cyclades-Z interrupt support code / logic;
- * Removed CTS handling from the driver -- this is now completely handled
- * by the firmware (Cyclades-Z only);
- * Flush RX on-board buffers on a port open (Cyclades-Z only);
- * Fixed handling of ASYNC_SPD_* TTY flags;
- * Module unload now unmaps all memory area allocated by ioremap;
- *
- * Revision 2.3.1.1 1999/07/15 16:45:53 ivan
- * Removed CY_PROC conditional compilation;
- * Implemented SMP-awareness for the driver;
- * Implemented a new ISA IRQ autoprobe that uses the irq_probe_[on|off]
- * functions;
- * The driver now accepts memory addresses (maddr=0xMMMMM) and IRQs
- * (irq=NN) as parameters (only for ISA boards);
- * Fixed bug in set_line_char that would prevent the Cyclades-Z
- * ports from being configured at speeds above 115.2Kbps;
- * Fixed bug in cy_set_termios that would prevent XON/XOFF flow control
- * switching from working properly;
- * The driver now only prints IRQ info for the Cyclades-Z if it's
- * configured to work in interrupt mode;
- *
- * Revision 2.2.2.3 1999/06/28 11:13:29 ivan
- * Added support for interrupt mode operation for the Z cards;
- * Removed the driver inactivity control for the Z;
- * Added a missing MOD_DEC_USE_COUNT in the cy_open function for when
- * the Z firmware is not loaded yet;
- * Replaced the "manual" Z Tx flush buffer by a call to a FW command of
- * same functionality;
- * Implemented workaround for IRQ setting loss on the PCI configuration
- * registers after a PCI bridge EEPROM reload (affects PLX9060 only);
- *
- * Revision 2.2.2.2 1999/05/14 17:18:15 ivan
- * /proc entry location changed to /proc/tty/driver/cyclades;
- * Added support to shared IRQ's (only for PCI boards);
- * Added support for Cobalt Qube2 systems;
- * IRQ [de]allocation scheme revisited;
- * BREAK implementation changed in order to make use of the 'break_ctl'
- * TTY facility;
- * Fixed typo in TTY structure field 'driver_name';
- * Included a PCI bridge reset and EEPROM reload in the board
- * initialization code (for both Y and Z series).
- *
- * Revision 2.2.2.1 1999/04/08 16:17:43 ivan
- * Fixed a bug in cy_wait_until_sent that was preventing the port to be
- * closed properly after a SIGINT;
- * Module usage counter scheme revisited;
- * Added support to the upcoming Y PCI boards (i.e., support to additional
- * PCI Device ID's).
- *
- * Revision 2.2.1.10 1999/01/20 16:14:29 ivan
- * Removed all unnecessary page-alignement operations in ioremap calls
- * (ioremap is currently safe for these operations).
- *
- * Revision 2.2.1.9 1998/12/30 18:18:30 ivan
- * Changed access to PLX PCI bridge registers from I/O to MMIO, in
- * order to make PLX9050-based boards work with certain motherboards.
- *
- * Revision 2.2.1.8 1998/11/13 12:46:20 ivan
- * cy_close function now resets (correctly) the tty->closing flag;
- * JIFFIES_DIFF macro fixed.
- *
- * Revision 2.2.1.7 1998/09/03 12:07:28 ivan
- * Fixed bug in cy_close function, which was not informing HW of
- * which port should have the reception disabled before doing so;
- * fixed Cyclom-8YoP hardware detection bug.
- *
- * Revision 2.2.1.6 1998/08/20 17:15:39 ivan
- * Fixed bug in cy_close function, which causes malfunction
- * of one of the first 4 ports when a higher port is closed
- * (Cyclom-Y only).
- *
- * Revision 2.2.1.5 1998/08/10 18:10:28 ivan
- * Fixed Cyclom-4Yo hardware detection bug.
- *
- * Revision 2.2.1.4 1998/08/04 11:02:50 ivan
- * /proc/cyclades implementation with great collaboration of
- * Marc Lewis <marc@blarg.net>;
- * cyy_interrupt was changed to avoid occurrence of kernel oopses
- * during PPP operation.
- *
- * Revision 2.2.1.3 1998/06/01 12:09:10 ivan
- * General code review in order to comply with 2.1 kernel standards;
- * data loss prevention for slow devices revisited (cy_wait_until_sent
- * was created);
- * removed conditional compilation for new/old PCI structure support
- * (now the driver only supports the new PCI structure).
- *
- * Revision 2.2.1.1 1998/03/19 16:43:12 ivan
- * added conditional compilation for new/old PCI structure support;
- * removed kernel series (2.0.x / 2.1.x) conditional compilation.
- *
- * Revision 2.1.1.3 1998/03/16 18:01:12 ivan
- * cleaned up the data loss fix;
- * fixed XON/XOFF handling once more (Cyclades-Z);
- * general review of the driver routines;
- * introduction of a mechanism to prevent data loss with slow
- * printers, by forcing a delay before closing the port.
- *
- * Revision 2.1.1.2 1998/02/17 16:50:00 ivan
- * fixed detection/handling of new CD1400 in Ye boards;
- * fixed XON/XOFF handling (Cyclades-Z);
- * fixed data loss caused by a premature port close;
- * introduction of a flag that holds the CD1400 version ID per port
- * (used by the CYGETCD1400VER new ioctl).
- *
- * Revision 2.1.1.1 1997/12/03 17:31:19 ivan
- * Code review for the module cleanup routine;
- * fixed RTS and DTR status report for new CD1400's in get_modem_info;
- * includes anonymous changes regarding signal_pending.
- *
- * Revision 2.1 1997/11/01 17:42:41 ivan
- * Changes in the driver to support Alpha systems (except 8Zo V_1);
- * BREAK fix for the Cyclades-Z boards;
- * driver inactivity control by FW implemented;
- * introduction of flag that allows driver to take advantage of
- * a special CD1400 feature related to HW flow control;
- * added support for the CD1400 rev. J (Cyclom-Y boards);
- * introduction of ioctls to:
- * - control the rtsdtr_inv flag (Cyclom-Y);
- * - control the rflow flag (Cyclom-Y);
- * - adjust the polling interval (Cyclades-Z);
- *
- * Revision 1.36.4.33 1997/06/27 19:00:00 ivan
- * Fixes related to kernel version conditional
- * compilation.
- *
- * Revision 1.36.4.32 1997/06/14 19:30:00 ivan
- * Compatibility issues between kernels 2.0.x and
- * 2.1.x (mainly related to clear_bit function).
- *
- * Revision 1.36.4.31 1997/06/03 15:30:00 ivan
- * Changes to define the memory window according to the
- * board type.
- *
- * Revision 1.36.4.30 1997/05/16 15:30:00 daniel
- * Changes to support new cycladesZ boards.
- *
- * Revision 1.36.4.29 1997/05/12 11:30:00 daniel
- * Merge of Bentson's and Daniel's version 1.36.4.28.
- * Corrects bug in cy_detect_pci: check if there are more
- * ports than the number of static structs allocated.
- * Warning message during initialization if this driver is
- * used with the new generation of cycladesZ boards. Those
- * will be supported only in next release of the driver.
- * Corrects bug in cy_detect_pci and cy_detect_isa that
- * returned wrong number of VALID boards, when a cyclomY
- * was found with no serial modules connected.
- * Changes to use current (2.1.x) kernel subroutine names
- * and created macros for compilation with 2.0.x kernel,
- * instead of the other way around.
- *
- * Revision 1.36.4.28 1997/05/?? ??:00:00 bentson
- * Change queue_task_irq_off to queue_task_irq.
- * The inline function queue_task_irq_off (tqueue.h)
- * was removed from latest releases of 2.1.x kernel.
- * Use of macro __init to mark the initialization
- * routines, so memory can be reused.
- * Also incorporate implementation of critical region
- * in function cleanup_module() created by anonymous
- * linuxer.
- *
- * Revision 1.36.4.28 1997/04/25 16:00:00 daniel
- * Change to support new firmware that solves DCD problem:
- * application could fail to receive SIGHUP signal when DCD
- * varying too fast.
- *
- * Revision 1.36.4.27 1997/03/26 10:30:00 daniel
- * Changed for support linux versions 2.1.X.
- * Backward compatible with linux versions 2.0.X.
- * Corrected illegal use of filler field in
- * CH_CTRL struct.
- * Deleted some debug messages.
- *
- * Revision 1.36.4.26 1997/02/27 12:00:00 daniel
- * Included check for NULL tty pointer in cyz_poll.
- *
- * Revision 1.36.4.25 1997/02/26 16:28:30 bentson
- * Bill Foster at Blarg! Online services noticed that
- * some of the switch elements of -Z modem control
- * lacked a closing "break;"
- *
- * Revision 1.36.4.24 1997/02/24 11:00:00 daniel
- * Changed low water threshold for buffer xmit_buf
- *
- * Revision 1.36.4.23 1996/12/02 21:50:16 bentson
- * Marcio provided fix to modem status fetch for -Z
- *
- * Revision 1.36.4.22 1996/10/28 22:41:17 bentson
- * improve mapping of -Z control page (thanks to Steve
- * Price <stevep@fa.tdktca.com> for help on this)
- *
- * Revision 1.36.4.21 1996/09/10 17:00:10 bentson
- * shift from CPU-bound to memcopy in cyz_polling operation
- *
- * Revision 1.36.4.20 1996/09/09 18:30:32 Bentson
- * Added support to set and report higher speeds.
- *
- * Revision 1.36.4.19c 1996/08/09 10:00:00 Marcio Saito
- * Some fixes in the HW flow control for the BETA release.
- * Don't try to register the IRQ.
- *
- * Revision 1.36.4.19 1996/08/08 16:23:18 Bentson
- * make sure "cyc" appears in all kernel messages; all soft interrupts
- * handled by same routine; recognize out-of-band reception; comment
- * out some diagnostic messages; leave RTS/CTS flow control to hardware;
- * fix race condition in -Z buffer management; only -Y needs to explicitly
- * flush chars; tidy up some startup messages;
- *
- * Revision 1.36.4.18 1996/07/25 18:57:31 bentson
- * shift MOD_INC_USE_COUNT location to match
- * serial.c; purge some diagnostic messages;
- *
- * Revision 1.36.4.17 1996/07/25 18:01:08 bentson
- * enable modem status messages and fetch & process them; note
- * time of last activity type for each port; set_line_char now
- * supports more than line 0 and treats 0 baud correctly;
- * get_modem_info senses rs_status;
- *
- * Revision 1.36.4.16 1996/07/20 08:43:15 bentson
- * barely works--now's time to turn on
- * more features 'til it breaks
- *
- * Revision 1.36.4.15 1996/07/19 22:30:06 bentson
- * check more -Z board status; shorten boot message
- *
- * Revision 1.36.4.14 1996/07/19 22:20:37 bentson
- * fix reference to ch_ctrl in startup; verify return
- * values from cyz_issue_cmd and cyz_update_channel;
- * more stuff to get modem control correct;
- *
- * Revision 1.36.4.13 1996/07/11 19:53:33 bentson
- * more -Z stuff folded in; re-order changes to put -Z stuff
- * after -Y stuff (to make changes clearer)
- *
- * Revision 1.36.4.12 1996/07/11 15:40:55 bentson
- * Add code to poll Cyclades-Z. Add code to get & set RS-232 control.
- * Add code to send break. Clear firmware ID word at startup (so
- * that other code won't talk to inactive board).
- *
- * Revision 1.36.4.11 1996/07/09 05:28:29 bentson
- * add code for -Z in set_line_char
- *
- * Revision 1.36.4.10 1996/07/08 19:28:37 bentson
- * fold more -Z stuff (or in some cases, error messages)
- * into driver; add text to "don't know what to do" messages.
- *
- * Revision 1.36.4.9 1996/07/08 18:38:38 bentson
- * moved compile-time flags near top of file; cosmetic changes
- * to narrow text (to allow 2-up printing); changed many declarations
- * to "static" to limit external symbols; shuffled code order to
- * coalesce -Y and -Z specific code, also to put internal functions
- * in order of tty_driver structure; added code to recognize -Z
- * ports (and for moment, do nothing or report error); add cy_startup
- * to parse boot command line for extra base addresses for ISA probes;
- *
- * Revision 1.36.4.8 1996/06/25 17:40:19 bentson
- * reorder some code, fix types of some vars (int vs. long),
- * add cy_setup to support user declared ISA addresses
- *
- * Revision 1.36.4.7 1996/06/21 23:06:18 bentson
- * dump ioctl based firmware load (it's now a user level
- * program); ensure uninitialzed ports cannot be used
- *
- * Revision 1.36.4.6 1996/06/20 23:17:19 bentson
- * rename vars and restructure some code
- *
- * Revision 1.36.4.5 1996/06/14 15:09:44 bentson
- * get right status back after boot load
- *
- * Revision 1.36.4.4 1996/06/13 19:51:44 bentson
- * successfully loads firmware
- *
- * Revision 1.36.4.3 1996/06/13 06:08:33 bentson
- * add more of the code for the boot/load ioctls
- *
- * Revision 1.36.4.2 1996/06/11 21:00:51 bentson
- * start to add Z functionality--starting with ioctl
- * for loading firmware
- *
- * Revision 1.36.4.1 1996/06/10 18:03:02 bentson
- * added code to recognize Z/PCI card at initialization; report
- * presence, but card is not initialized (because firmware needs
- * to be loaded)
- *
- * Revision 1.36.3.8 1996/06/07 16:29:00 bentson
- * starting minor number at zero; added missing verify_area
- * as noted by Heiko Eißfeldt <heiko@colossus.escape.de>
- *
- * Revision 1.36.3.7 1996/04/19 21:06:18 bentson
- * remove unneeded boot message & fix CLOCAL hardware flow
- * control (Miquel van Smoorenburg <miquels@Q.cistron.nl>);
- * remove unused diagnostic statements; minor 0 is first;
- *
- * Revision 1.36.3.6 1996/03/13 13:21:17 marcio
- * The kernel function vremap (available only in later 1.3.xx kernels)
- * allows the access to memory addresses above the RAM. This revision
- * of the driver supports PCI boards below 1Mb (device id 0x100) and
- * above 1Mb (device id 0x101).
- *
- * Revision 1.36.3.5 1996/03/07 15:20:17 bentson
- * Some global changes to interrupt handling spilled into
- * this driver--mostly unused arguments in system function
- * calls. Also added change by Marcio Saito which should
- * reduce lost interrupts at startup by fast processors.
- *
- * Revision 1.36.3.4 1995/11/13 20:45:10 bentson
- * Changes by Corey Minyard <minyard@wf-rch.cirr.com> distributed
- * in 1.3.41 kernel to remove a possible race condition, extend
- * some error messages, and let the driver run as a loadable module
- * Change by Alan Wendt <alan@ez0.ezlink.com> to remove a
- * possible race condition.
- * Change by Marcio Saito <marcio@cyclades.com> to fix PCI addressing.
- *
- * Revision 1.36.3.3 1995/11/13 19:44:48 bentson
- * Changes by Linus Torvalds in 1.3.33 kernel distribution
- * required due to reordering of driver initialization.
- * Drivers are now initialized *after* memory management.
- *
- * Revision 1.36.3.2 1995/09/08 22:07:14 bentson
- * remove printk from ISR; fix typo
- *
- * Revision 1.36.3.1 1995/09/01 12:00:42 marcio
- * Minor fixes in the PCI board support. PCI function calls in
- * conditional compilation (CONFIG_PCI). Thanks to Jim Duncan
- * <duncan@okay.com>. "bad serial count" message removed.
- *
- * Revision 1.36.3 1995/08/22 09:19:42 marcio
- * Cyclom-Y/PCI support added. Changes in the cy_init routine and
- * board initialization. Changes in the boot messages. The driver
- * supports up to 4 boards and 64 ports by default.
- *
- * Revision 1.36.1.4 1995/03/29 06:14:14 bentson
- * disambiguate between Cyclom-16Y and Cyclom-32Ye;
- *
- * Revision 1.36.1.3 1995/03/23 22:15:35 bentson
- * add missing break in modem control block in ioctl switch statement
- * (discovered by Michael Edward Chastain <mec@jobe.shell.portal.com>);
- *
- * Revision 1.36.1.2 1995/03/22 19:16:22 bentson
- * make sure CTS flow control is set as soon as possible (thanks
- * to note from David Lambert <lambert@chesapeake.rps.slb.com>);
- *
- * Revision 1.36.1.1 1995/03/13 15:44:43 bentson
- * initialize defaults for receive threshold and stale data timeout;
- * cosmetic changes;
- *
- * Revision 1.36 1995/03/10 23:33:53 bentson
- * added support of chips 4-7 in 32 port Cyclom-Ye;
- * fix cy_interrupt pointer dereference problem
- * (Joe Portman <baron@aa.net>);
- * give better error response if open is attempted on non-existent port
- * (Zachariah Vaum <jchryslr@netcom.com>);
- * correct command timeout (Kenneth Lerman <lerman@@seltd.newnet.com>);
- * conditional compilation for -16Y on systems with fast, noisy bus;
- * comment out diagnostic print function;
- * cleaned up table of base addresses;
- * set receiver time-out period register to correct value,
- * set receive threshold to better default values,
- * set chip timer to more accurate 200 Hz ticking,
- * add code to monitor and modify receive parameters
- * (Rik Faith <faith@cs.unc.edu> Nick Simicich
- * <njs@scifi.emi.net>);
- *
- * Revision 1.35 1994/12/16 13:54:18 steffen
- * additional patch by Marcio Saito for board detection
- * Accidently left out in 1.34
- *
- * Revision 1.34 1994/12/10 12:37:12 steffen
- * This is the corrected version as suggested by Marcio Saito
- *
- * Revision 1.33 1994/12/01 22:41:18 bentson
- * add hooks to support more high speeds directly; add tytso
- * patch regarding CLOCAL wakeups
- *
- * Revision 1.32 1994/11/23 19:50:04 bentson
- * allow direct kernel control of higher signalling rates;
- * look for cards at additional locations
- *
- * Revision 1.31 1994/11/16 04:33:28 bentson
- * ANOTHER fix from Corey Minyard, minyard@wf-rch.cirr.com--
- * a problem in chars_in_buffer has been resolved by some
- * small changes; this should yield smoother output
- *
- * Revision 1.30 1994/11/16 04:28:05 bentson
- * Fix from Corey Minyard, Internet: minyard@metronet.com,
- * UUCP: minyard@wf-rch.cirr.com, WORK: minyardbnr.ca, to
- * cy_hangup that appears to clear up much (all?) of the
- * DTR glitches; also he's added/cleaned-up diagnostic messages
- *
- * Revision 1.29 1994/11/16 04:16:07 bentson
- * add change proposed by Ralph Sims, ralphs@halcyon.com, to
- * operate higher speeds in same way as other serial ports;
- * add more serial ports (for up to two 16-port muxes).
- *
- * Revision 1.28 1994/11/04 00:13:16 root
- * turn off diagnostic messages
- *
- * Revision 1.27 1994/11/03 23:46:37 root
- * bunch of changes to bring driver into greater conformance
- * with the serial.c driver (looking for missed fixes)
- *
- * Revision 1.26 1994/11/03 22:40:36 root
- * automatic interrupt probing fixed.
- *
- * Revision 1.25 1994/11/03 20:17:02 root
- * start to implement auto-irq
- *
- * Revision 1.24 1994/11/03 18:01:55 root
- * still working on modem signals--trying not to drop DTR
- * during the getty/login processes
- *
- * Revision 1.23 1994/11/03 17:51:36 root
- * extend baud rate support; set receive threshold as function
- * of baud rate; fix some problems with RTS/CTS;
- *
- * Revision 1.22 1994/11/02 18:05:35 root
- * changed arguments to udelay to type long to get
- * delays to be of correct duration
- *
- * Revision 1.21 1994/11/02 17:37:30 root
- * employ udelay (after calibrating loops_per_second earlier
- * in init/main.c) instead of using home-grown delay routines
- *
- * Revision 1.20 1994/11/02 03:11:38 root
- * cy_chars_in_buffer forces a return value of 0 to let
- * login work (don't know why it does); some functions
- * that were returning EFAULT, now executes the code;
- * more work on deciding when to disable xmit interrupts;
- *
- * Revision 1.19 1994/11/01 20:10:14 root
- * define routine to start transmission interrupts (by enabling
- * transmit interrupts); directly enable/disable modem interrupts;
- *
- * Revision 1.18 1994/11/01 18:40:45 bentson
- * Don't always enable transmit interrupts in startup; interrupt on
- * TxMpty instead of TxRdy to help characters get out before shutdown;
- * restructure xmit interrupt to check for chars first and quit if
- * none are ready to go; modem status (MXVRx) is upright, _not_ inverted
- * (to my view);
- *
- * Revision 1.17 1994/10/30 04:39:45 bentson
- * rename serial_driver and callout_driver to cy_serial_driver and
- * cy_callout_driver to avoid linkage interference; initialize
- * info->type to PORT_CIRRUS; ruggedize paranoia test; elide ->port
- * from cyclades_port structure; add paranoia check to cy_close;
- *
- * Revision 1.16 1994/10/30 01:14:33 bentson
- * change major numbers; add some _early_ return statements;
- *
- * Revision 1.15 1994/10/29 06:43:15 bentson
- * final tidying up for clean compile; enable some error reporting
- *
- * Revision 1.14 1994/10/28 20:30:22 Bentson
- * lots of changes to drag the driver towards the new tty_io
- * structures and operation. not expected to work, but may
- * compile cleanly.
- *
- * Revision 1.13 1994/07/21 23:08:57 Bentson
- * add some diagnostic cruft; support 24 lines (for testing
- * both -8Y and -16Y cards; be more thorough in servicing all
- * chips during interrupt; add "volatile" a few places to
- * circumvent compiler optimizations; fix base & offset
- * computations in block_til_ready (was causing chip 0 to
- * stop operation)
- *
- * Revision 1.12 1994/07/19 16:42:11 Bentson
- * add some hackery for kernel version 1.1.8; expand
- * error messages; refine timing for delay loops and
- * declare loop params volatile
- *
- * Revision 1.11 1994/06/11 21:53:10 bentson
- * get use of save_car right in transmit interrupt service
- *
- * Revision 1.10.1.1 1994/06/11 21:31:18 bentson
- * add some diagnostic printing; try to fix save_car stuff
- *
- * Revision 1.10 1994/06/11 20:36:08 bentson
- * clean up compiler warnings
- *
- * Revision 1.9 1994/06/11 19:42:46 bentson
- * added a bunch of code to support modem signalling
- *
- * Revision 1.8 1994/06/11 17:57:07 bentson
- * recognize break & parity error
- *
- * Revision 1.7 1994/06/05 05:51:34 bentson
- * Reorder baud table to be monotonic; add cli to CP; discard
- * incoming characters and status if the line isn't open; start to
- * fold code into cy_throttle; start to port get_serial_info,
- * set_serial_info, get_modem_info, set_modem_info, and send_break
- * from serial.c; expand cy_ioctl; relocate and expand config_setup;
- * get flow control characters from tty struct; invalidate ports w/o
- * hardware;
- *
- * Revision 1.6 1994/05/31 18:42:21 bentson
- * add a loop-breaker in the interrupt service routine;
- * note when port is initialized so that it can be shut
- * down under the right conditions; receive works without
- * any obvious errors
- *
- * Revision 1.5 1994/05/30 00:55:02 bentson
- * transmit works without obvious errors
- *
- * Revision 1.4 1994/05/27 18:46:27 bentson
- * incorporated more code from lib_y.c; can now print short
- * strings under interrupt control to port zero; seems to
- * select ports/channels/lines correctly
- *
- * Revision 1.3 1994/05/25 22:12:44 bentson
- * shifting from multi-port on a card to proper multiplexor
- * data structures; added skeletons of most routines
- *
- * Revision 1.2 1994/05/19 13:21:43 bentson
- * start to crib from other sources
- *
*/
-#define CY_VERSION "2.5"
+#define CY_VERSION "2.6"
/* If you need to install more boards than NR_CARDS, change the constant
in the definition below. No other change is necessary to support up to
@@ -647,9 +79,7 @@
#include <linux/firmware.h>
#include <linux/device.h>
-#include <asm/system.h>
#include <linux/io.h>
-#include <asm/irq.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
@@ -659,13 +89,11 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-static void cy_throttle(struct tty_struct *tty);
static void cy_send_xchar(struct tty_struct *tty, char ch);
#ifndef SERIAL_XMIT_SIZE
#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096))
#endif
-#define WAKEUP_CHARS 256
#define STD_COM_FLAGS (0)
@@ -755,25 +183,25 @@ static int cy_next_channel; /* next minor available */
* HI VHI
* 20
*/
-static int baud_table[] = {
+static const int baud_table[] = {
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
230400, 0
};
-static char baud_co_25[] = { /* 25 MHz clock option table */
+static const char baud_co_25[] = { /* 25 MHz clock option table */
/* value => 00 01 02 03 04 */
/* divide by 8 32 128 512 2048 */
0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-static char baud_bpr_25[] = { /* 25 MHz baud rate period table */
+static const char baud_bpr_25[] = { /* 25 MHz baud rate period table */
0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
};
-static char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
+static const char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
/* value => 00 01 02 03 04 */
/* divide by 8 32 128 512 2048 */
0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
@@ -781,13 +209,13 @@ static char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
0x00
};
-static char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
+static const char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
0x21
};
-static char baud_cor3[] = { /* receive threshold */
+static const char baud_cor3[] = { /* receive threshold */
0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
0x07
@@ -804,7 +232,7 @@ static char baud_cor3[] = { /* receive threshold */
* cables.
*/
-static char rflow_thr[] = { /* rflow threshold */
+static const char rflow_thr[] = { /* rflow threshold */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
0x0a
@@ -813,7 +241,7 @@ static char rflow_thr[] = { /* rflow threshold */
/* The Cyclom-Ye has placed the sequential chips in non-sequential
* address order. This look-up table overcomes that problem.
*/
-static int cy_chip_offset[] = { 0x0000,
+static const unsigned int cy_chip_offset[] = { 0x0000,
0x0400,
0x0800,
0x0C00,
@@ -826,7 +254,7 @@ static int cy_chip_offset[] = { 0x0000,
/* PCI related definitions */
#ifdef CONFIG_PCI
-static struct pci_device_id cy_pci_dev_id[] __devinitdata = {
+static const struct pci_device_id cy_pci_dev_id[] = {
/* PCI < 1Mb */
{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },
/* PCI > 1Mb */
@@ -849,7 +277,7 @@ MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
#endif
static void cy_start(struct tty_struct *);
-static void set_line_char(struct cyclades_port *);
+static void cy_set_line_char(struct cyclades_port *, struct tty_struct *);
static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
#ifdef CONFIG_ISA
static unsigned detect_isa_irq(void __iomem *);
@@ -868,6 +296,20 @@ static void cyz_rx_restart(unsigned long);
static struct timer_list cyz_rx_full_timer[NR_PORTS];
#endif /* CONFIG_CYZ_INTR */
+static inline void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val)
+{
+ struct cyclades_card *card = port->card;
+
+ cy_writeb(port->u.cyy.base_addr + (reg << card->bus_index), val);
+}
+
+static inline u8 cyy_readb(struct cyclades_port *port, u32 reg)
+{
+ struct cyclades_card *card = port->card;
+
+ return readb(port->u.cyy.base_addr + (reg << card->bus_index));
+}
+
static inline bool cy_is_Z(struct cyclades_card *card)
{
return card->num_chips == (unsigned int)-1;
@@ -892,7 +334,7 @@ static inline bool cyz_is_loaded(struct cyclades_card *card)
}
static inline int serial_paranoia_check(struct cyclades_port *info,
- char *name, const char *routine)
+ const char *name, const char *routine)
{
#ifdef SERIAL_PARANOIA_CHECK
if (!info) {
@@ -908,7 +350,7 @@ static inline int serial_paranoia_check(struct cyclades_port *info,
}
#endif
return 0;
-} /* serial_paranoia_check */
+}
/***********************************************************/
/********* Start of block of Cyclom-Y specific code ********/
@@ -920,13 +362,14 @@ static inline int serial_paranoia_check(struct cyclades_port *info,
This function is only called from inside spinlock-protected code.
*/
-static int cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index)
+static int __cyy_issue_cmd(void __iomem *base_addr, u8 cmd, int index)
{
+ void __iomem *ccr = base_addr + (CyCCR << index);
unsigned int i;
/* Check to see that the previous command has completed */
for (i = 0; i < 100; i++) {
- if (readb(base_addr + (CyCCR << index)) == 0)
+ if (readb(ccr) == 0)
break;
udelay(10L);
}
@@ -936,10 +379,16 @@ static int cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index)
return -1;
/* Issue the new command */
- cy_writeb(base_addr + (CyCCR << index), cmd);
+ cy_writeb(ccr, cmd);
return 0;
-} /* cyy_issue_cmd */
+}
+
+static inline int cyy_issue_cmd(struct cyclades_port *port, u8 cmd)
+{
+ return __cyy_issue_cmd(port->u.cyy.base_addr, cmd,
+ port->card->bus_index);
+}
#ifdef CONFIG_ISA
/* ISA interrupt detection code */
@@ -959,12 +408,12 @@ static unsigned detect_isa_irq(void __iomem *address)
irqs = probe_irq_on();
/* Wait ... */
- udelay(5000L);
+ msleep(5);
/* Enable the Tx interrupts on the CD1400 */
local_irq_save(flags);
cy_writeb(address + (CyCAR << index), 0);
- cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
+ __cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
cy_writeb(address + (CyCAR << index), 0);
cy_writeb(address + (CySRER << index),
@@ -972,7 +421,7 @@ static unsigned detect_isa_irq(void __iomem *address)
local_irq_restore(flags);
/* Wait ... */
- udelay(5000L);
+ msleep(5);
/* Check which interrupt is in use */
irq = probe_irq_off(irqs);
@@ -998,7 +447,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
struct cyclades_port *info;
struct tty_struct *tty;
int len, index = cinfo->bus_index;
- u8 save_xir, channel, save_car, data, char_count;
+ u8 ivr, save_xir, channel, save_car, data, char_count;
#ifdef CY_DEBUG_INTERRUPTS
printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
@@ -1007,26 +456,25 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
save_xir = readb(base_addr + (CyRIR << index));
channel = save_xir & CyIRChannel;
info = &cinfo->ports[channel + chip * 4];
- save_car = readb(base_addr + (CyCAR << index));
- cy_writeb(base_addr + (CyCAR << index), save_xir);
+ save_car = cyy_readb(info, CyCAR);
+ cyy_writeb(info, CyCAR, save_xir);
+ ivr = cyy_readb(info, CyRIVR) & CyIVRMask;
+ tty = tty_port_tty_get(&info->port);
/* if there is nowhere to put the data, discard it */
- if (info->port.tty == NULL) {
- if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) ==
- CyIVRRxEx) { /* exception */
- data = readb(base_addr + (CyRDSR << index));
+ if (tty == NULL) {
+ if (ivr == CyIVRRxEx) { /* exception */
+ data = cyy_readb(info, CyRDSR);
} else { /* normal character reception */
- char_count = readb(base_addr + (CyRDCR << index));
+ char_count = cyy_readb(info, CyRDCR);
while (char_count--)
- data = readb(base_addr + (CyRDSR << index));
+ data = cyy_readb(info, CyRDSR);
}
goto end;
}
/* there is an open port for this data */
- tty = info->port.tty;
- if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) ==
- CyIVRRxEx) { /* exception */
- data = readb(base_addr + (CyRDSR << index));
+ if (ivr == CyIVRRxEx) { /* exception */
+ data = cyy_readb(info, CyRDSR);
/* For statistics only */
if (data & CyBREAK)
@@ -1040,28 +488,29 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
if (data & info->ignore_status_mask) {
info->icount.rx++;
+ tty_kref_put(tty);
return;
}
if (tty_buffer_request_room(tty, 1)) {
if (data & info->read_status_mask) {
if (data & CyBREAK) {
tty_insert_flip_char(tty,
- readb(base_addr + (CyRDSR <<
- index)), TTY_BREAK);
+ cyy_readb(info, CyRDSR),
+ TTY_BREAK);
info->icount.rx++;
if (info->port.flags & ASYNC_SAK)
do_SAK(tty);
} else if (data & CyFRAME) {
tty_insert_flip_char(tty,
- readb(base_addr + (CyRDSR <<
- index)), TTY_FRAME);
+ cyy_readb(info, CyRDSR),
+ TTY_FRAME);
info->icount.rx++;
info->idle_stats.frame_errs++;
} else if (data & CyPARITY) {
/* Pieces of seven... */
tty_insert_flip_char(tty,
- readb(base_addr + (CyRDSR <<
- index)), TTY_PARITY);
+ cyy_readb(info, CyRDSR),
+ TTY_PARITY);
info->icount.rx++;
info->idle_stats.parity_errs++;
} else if (data & CyOVERRUN) {
@@ -1073,8 +522,8 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
the next incoming character.
*/
tty_insert_flip_char(tty,
- readb(base_addr + (CyRDSR <<
- index)), TTY_FRAME);
+ cyy_readb(info, CyRDSR),
+ TTY_FRAME);
info->icount.rx++;
info->idle_stats.overruns++;
/* These two conditions may imply */
@@ -1098,7 +547,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
}
} else { /* normal character reception */
/* load # chars available from the chip */
- char_count = readb(base_addr + (CyRDCR << index));
+ char_count = cyy_readb(info, CyRDCR);
#ifdef CY_ENABLE_MONITORING
++info->mon.int_count;
@@ -1109,7 +558,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
#endif
len = tty_buffer_request_room(tty, char_count);
while (len--) {
- data = readb(base_addr + (CyRDSR << index));
+ data = cyy_readb(info, CyRDSR);
tty_insert_flip_char(tty, data, TTY_NORMAL);
info->idle_stats.recv_bytes++;
info->icount.rx++;
@@ -1120,16 +569,18 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
info->idle_stats.recv_idle = jiffies;
}
tty_schedule_flip(tty);
+ tty_kref_put(tty);
end:
/* end of service */
- cy_writeb(base_addr + (CyRIR << index), save_xir & 0x3f);
- cy_writeb(base_addr + (CyCAR << index), save_car);
+ cyy_writeb(info, CyRIR, save_xir & 0x3f);
+ cyy_writeb(info, CyCAR, save_car);
}
static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
void __iomem *base_addr)
{
struct cyclades_port *info;
+ struct tty_struct *tty;
int char_count, index = cinfo->bus_index;
u8 save_xir, channel, save_car, outch;
@@ -1153,9 +604,9 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
goto end;
}
info = &cinfo->ports[channel + chip * 4];
- if (info->port.tty == NULL) {
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) & ~CyTxRdy);
+ tty = tty_port_tty_get(&info->port);
+ if (tty == NULL) {
+ cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
goto end;
}
@@ -1164,7 +615,7 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
if (info->x_char) { /* send special char */
outch = info->x_char;
- cy_writeb(base_addr + (CyTDR << index), outch);
+ cyy_writeb(info, CyTDR, outch);
char_count--;
info->icount.tx++;
info->x_char = 0;
@@ -1172,14 +623,14 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
if (info->breakon || info->breakoff) {
if (info->breakon) {
- cy_writeb(base_addr + (CyTDR << index), 0);
- cy_writeb(base_addr + (CyTDR << index), 0x81);
+ cyy_writeb(info, CyTDR, 0);
+ cyy_writeb(info, CyTDR, 0x81);
info->breakon = 0;
char_count -= 2;
}
if (info->breakoff) {
- cy_writeb(base_addr + (CyTDR << index), 0);
- cy_writeb(base_addr + (CyTDR << index), 0x83);
+ cyy_writeb(info, CyTDR, 0);
+ cyy_writeb(info, CyTDR, 0x83);
info->breakoff = 0;
char_count -= 2;
}
@@ -1187,27 +638,23 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
while (char_count-- > 0) {
if (!info->xmit_cnt) {
- if (readb(base_addr + (CySRER << index)) & CyTxMpty) {
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) &
- ~CyTxMpty);
+ if (cyy_readb(info, CySRER) & CyTxMpty) {
+ cyy_writeb(info, CySRER,
+ cyy_readb(info, CySRER) & ~CyTxMpty);
} else {
- cy_writeb(base_addr + (CySRER << index),
- (readb(base_addr + (CySRER << index)) &
- ~CyTxRdy) | CyTxMpty);
+ cyy_writeb(info, CySRER, CyTxMpty |
+ (cyy_readb(info, CySRER) & ~CyTxRdy));
}
goto done;
}
if (info->port.xmit_buf == NULL) {
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) &
- ~CyTxRdy);
+ cyy_writeb(info, CySRER,
+ cyy_readb(info, CySRER) & ~CyTxRdy);
goto done;
}
- if (info->port.tty->stopped || info->port.tty->hw_stopped) {
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) &
- ~CyTxRdy);
+ if (tty->stopped || tty->hw_stopped) {
+ cyy_writeb(info, CySRER,
+ cyy_readb(info, CySRER) & ~CyTxRdy);
goto done;
}
/* Because the Embedded Transmit Commands have been enabled,
@@ -1224,15 +671,15 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
info->xmit_cnt--;
info->xmit_tail = (info->xmit_tail + 1) &
(SERIAL_XMIT_SIZE - 1);
- cy_writeb(base_addr + (CyTDR << index), outch);
+ cyy_writeb(info, CyTDR, outch);
info->icount.tx++;
} else {
if (char_count > 1) {
info->xmit_cnt--;
info->xmit_tail = (info->xmit_tail + 1) &
(SERIAL_XMIT_SIZE - 1);
- cy_writeb(base_addr + (CyTDR << index), outch);
- cy_writeb(base_addr + (CyTDR << index), 0);
+ cyy_writeb(info, CyTDR, outch);
+ cyy_writeb(info, CyTDR, 0);
info->icount.tx++;
char_count--;
}
@@ -1240,17 +687,19 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
}
done:
- tty_wakeup(info->port.tty);
+ tty_wakeup(tty);
+ tty_kref_put(tty);
end:
/* end of service */
- cy_writeb(base_addr + (CyTIR << index), save_xir & 0x3f);
- cy_writeb(base_addr + (CyCAR << index), save_car);
+ cyy_writeb(info, CyTIR, save_xir & 0x3f);
+ cyy_writeb(info, CyCAR, save_car);
}
static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
void __iomem *base_addr)
{
struct cyclades_port *info;
+ struct tty_struct *tty;
int index = cinfo->bus_index;
u8 save_xir, channel, save_car, mdm_change, mdm_status;
@@ -1258,13 +707,14 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
save_xir = readb(base_addr + (CyMIR << index));
channel = save_xir & CyIRChannel;
info = &cinfo->ports[channel + chip * 4];
- save_car = readb(base_addr + (CyCAR << index));
- cy_writeb(base_addr + (CyCAR << index), save_xir);
+ save_car = cyy_readb(info, CyCAR);
+ cyy_writeb(info, CyCAR, save_xir);
- mdm_change = readb(base_addr + (CyMISR << index));
- mdm_status = readb(base_addr + (CyMSVR1 << index));
+ mdm_change = cyy_readb(info, CyMISR);
+ mdm_status = cyy_readb(info, CyMSVR1);
- if (!info->port.tty)
+ tty = tty_port_tty_get(&info->port);
+ if (!tty)
goto end;
if (mdm_change & CyANY_DELTA) {
@@ -1282,31 +732,28 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
}
if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) {
- if (!(mdm_status & CyDCD)) {
- tty_hangup(info->port.tty);
- info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
- }
- wake_up_interruptible(&info->port.open_wait);
+ if (mdm_status & CyDCD)
+ wake_up_interruptible(&info->port.open_wait);
+ else
+ tty_hangup(tty);
}
if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) {
- if (info->port.tty->hw_stopped) {
+ if (tty->hw_stopped) {
if (mdm_status & CyCTS) {
/* cy_start isn't used
because... !!! */
- info->port.tty->hw_stopped = 0;
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) |
- CyTxRdy);
- tty_wakeup(info->port.tty);
+ tty->hw_stopped = 0;
+ cyy_writeb(info, CySRER,
+ cyy_readb(info, CySRER) | CyTxRdy);
+ tty_wakeup(tty);
}
} else {
if (!(mdm_status & CyCTS)) {
/* cy_stop isn't used
because ... !!! */
- info->port.tty->hw_stopped = 1;
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) &
- ~CyTxRdy);
+ tty->hw_stopped = 1;
+ cyy_writeb(info, CySRER,
+ cyy_readb(info, CySRER) & ~CyTxRdy);
}
}
}
@@ -1314,10 +761,11 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
}
if (mdm_change & CyRI) {
}*/
+ tty_kref_put(tty);
end:
/* end of service */
- cy_writeb(base_addr + (CyMIR << index), save_xir & 0x3f);
- cy_writeb(base_addr + (CyCAR << index), save_car);
+ cyy_writeb(info, CyMIR, save_xir & 0x3f);
+ cyy_writeb(info, CyCAR, save_car);
}
/* The real interrupt service routine is called
@@ -1388,6 +836,56 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
} /* cyy_interrupt */
+static void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set,
+ unsigned int clear)
+{
+ struct cyclades_card *card = info->card;
+ int channel = info->line - card->first_line;
+ u32 rts, dtr, msvrr, msvrd;
+
+ channel &= 0x03;
+
+ if (info->rtsdtr_inv) {
+ msvrr = CyMSVR2;
+ msvrd = CyMSVR1;
+ rts = CyDTR;
+ dtr = CyRTS;
+ } else {
+ msvrr = CyMSVR1;
+ msvrd = CyMSVR2;
+ rts = CyRTS;
+ dtr = CyDTR;
+ }
+ if (set & TIOCM_RTS) {
+ cyy_writeb(info, CyCAR, channel);
+ cyy_writeb(info, msvrr, rts);
+ }
+ if (clear & TIOCM_RTS) {
+ cyy_writeb(info, CyCAR, channel);
+ cyy_writeb(info, msvrr, ~rts);
+ }
+ if (set & TIOCM_DTR) {
+ cyy_writeb(info, CyCAR, channel);
+ cyy_writeb(info, msvrd, dtr);
+#ifdef CY_DEBUG_DTR
+ printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ cyy_readb(info, CyMSVR1),
+ cyy_readb(info, CyMSVR2));
+#endif
+ }
+ if (clear & TIOCM_DTR) {
+ cyy_writeb(info, CyCAR, channel);
+ cyy_writeb(info, msvrd, ~dtr);
+#ifdef CY_DEBUG_DTR
+ printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ cyy_readb(info, CyMSVR1),
+ cyy_readb(info, CyMSVR2));
+#endif
+ }
+}
+
/***********************************************************/
/********* End of block of Cyclom-Y specific code **********/
/******** Start of block of Cyclades-Z specific code *******/
@@ -1397,15 +895,9 @@ static int
cyz_fetch_msg(struct cyclades_card *cinfo,
__u32 *channel, __u8 *cmd, __u32 *param)
{
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
unsigned long loc_doorbell;
- firm_id = cinfo->base_addr + ID_ADDRESS;
- zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
-
loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
if (loc_doorbell) {
*cmd = (char)(0xff & loc_doorbell);
@@ -1421,19 +913,13 @@ static int
cyz_issue_cmd(struct cyclades_card *cinfo,
__u32 channel, __u8 cmd, __u32 param)
{
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
__u32 __iomem *pci_doorbell;
unsigned int index;
- firm_id = cinfo->base_addr + ID_ADDRESS;
if (!cyz_is_loaded(cinfo))
return -1;
- zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
-
index = 0;
pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
while ((readl(pci_doorbell) & 0xff) != 0) {
@@ -1448,11 +934,10 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
return 0;
} /* cyz_issue_cmd */
-static void cyz_handle_rx(struct cyclades_port *info,
- struct BUF_CTRL __iomem *buf_ctrl)
+static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
{
+ struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
struct cyclades_card *cinfo = info->card;
- struct tty_struct *tty = info->port.tty;
unsigned int char_count;
int len;
#ifdef BLOCKMOVE
@@ -1541,11 +1026,10 @@ static void cyz_handle_rx(struct cyclades_port *info,
}
}
-static void cyz_handle_tx(struct cyclades_port *info,
- struct BUF_CTRL __iomem *buf_ctrl)
+static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
{
+ struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
struct cyclades_card *cinfo = info->card;
- struct tty_struct *tty = info->port.tty;
u8 data;
unsigned int char_count;
#ifdef BLOCKMOVE
@@ -1620,34 +1104,24 @@ ztxdone:
static void cyz_handle_cmd(struct cyclades_card *cinfo)
{
+ struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
struct tty_struct *tty;
struct cyclades_port *info;
- static struct FIRM_ID __iomem *firm_id;
- static struct ZFW_CTRL __iomem *zfw_ctrl;
- static struct BOARD_CTRL __iomem *board_ctrl;
- static struct CH_CTRL __iomem *ch_ctrl;
- static struct BUF_CTRL __iomem *buf_ctrl;
__u32 channel, param, fw_ver;
__u8 cmd;
int special_count;
int delta_count;
- firm_id = cinfo->base_addr + ID_ADDRESS;
- zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
fw_ver = readl(&board_ctrl->fw_version);
while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
special_count = 0;
delta_count = 0;
info = &cinfo->ports[channel];
- tty = info->port.tty;
+ tty = tty_port_tty_get(&info->port);
if (tty == NULL)
continue;
- ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
- buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
-
switch (cmd) {
case C_CM_PR_ERROR:
tty_insert_flip_char(tty, 0, TTY_PARITY);
@@ -1668,15 +1142,12 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
info->icount.dcd++;
delta_count++;
if (info->port.flags & ASYNC_CHECK_CD) {
- if ((fw_ver > 241 ? ((u_long) param) :
- readl(&ch_ctrl->rs_status)) &
- C_RS_DCD) {
- wake_up_interruptible(&info->port.open_wait);
- } else {
- tty_hangup(info->port.tty);
+ u32 dcd = fw_ver > 241 ? param :
+ readl(&info->u.cyz.ch_ctrl->rs_status);
+ if (dcd & C_RS_DCD)
wake_up_interruptible(&info->port.open_wait);
- info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
- }
+ else
+ tty_hangup(tty);
}
break;
case C_CM_MCTS:
@@ -1705,7 +1176,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
"port %ld\n", info->card, channel);
#endif
- cyz_handle_rx(info, buf_ctrl);
+ cyz_handle_rx(info, tty);
break;
case C_CM_TXBEMPTY:
case C_CM_TXLOWWM:
@@ -1715,7 +1186,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
"port %ld\n", info->card, channel);
#endif
- cyz_handle_tx(info, buf_ctrl);
+ cyz_handle_tx(info, tty);
break;
#endif /* CONFIG_CYZ_INTR */
case C_CM_FATAL:
@@ -1728,6 +1199,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
wake_up_interruptible(&info->delta_msr_wait);
if (special_count)
tty_schedule_flip(tty);
+ tty_kref_put(tty);
}
}
@@ -1773,10 +1245,6 @@ static void cyz_poll(unsigned long arg)
{
struct cyclades_card *cinfo;
struct cyclades_port *info;
- struct tty_struct *tty;
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BUF_CTRL __iomem *buf_ctrl;
unsigned long expires = jiffies + HZ;
unsigned int port, card;
@@ -1788,10 +1256,6 @@ static void cyz_poll(unsigned long arg)
if (!cyz_is_loaded(cinfo))
continue;
- firm_id = cinfo->base_addr + ID_ADDRESS;
- zfw_ctrl = cinfo->base_addr +
- (readl(&firm_id->zfwctrl_addr) & 0xfffff);
-
/* Skip first polling cycle to avoid racing conditions with the FW */
if (!cinfo->intr_enabled) {
cinfo->intr_enabled = 1;
@@ -1801,13 +1265,17 @@ static void cyz_poll(unsigned long arg)
cyz_handle_cmd(cinfo);
for (port = 0; port < cinfo->nports; port++) {
+ struct tty_struct *tty;
+
info = &cinfo->ports[port];
- tty = info->port.tty;
- buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
+ tty = tty_port_tty_get(&info->port);
+ /* OK to pass NULL to the handle functions below.
+ They need to drop the data in that case. */
if (!info->throttle)
- cyz_handle_rx(info, buf_ctrl);
- cyz_handle_tx(info, buf_ctrl);
+ cyz_handle_rx(info, tty);
+ cyz_handle_tx(info, tty);
+ tty_kref_put(tty);
}
/* poll every 'cyz_polling_cycle' period */
expires = jiffies + cyz_polling_cycle;
@@ -1823,13 +1291,12 @@ static void cyz_poll(unsigned long arg)
/* This is called whenever a port becomes active;
interrupts are enabled and DTR & RTS are turned on.
*/
-static int startup(struct cyclades_port *info)
+static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
{
struct cyclades_card *card;
unsigned long flags;
int retval = 0;
- void __iomem *base_addr;
- int chip, channel, index;
+ int channel;
unsigned long page;
card = info->card;
@@ -1841,15 +1308,11 @@ static int startup(struct cyclades_port *info)
spin_lock_irqsave(&card->card_lock, flags);
- if (info->port.flags & ASYNC_INITIALIZED) {
- free_page(page);
+ if (info->port.flags & ASYNC_INITIALIZED)
goto errout;
- }
if (!info->type) {
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
- free_page(page);
+ set_bit(TTY_IO_ERROR, &tty->flags);
goto errout;
}
@@ -1860,96 +1323,53 @@ static int startup(struct cyclades_port *info)
spin_unlock_irqrestore(&card->card_lock, flags);
- set_line_char(info);
+ cy_set_line_char(info, tty);
if (!cy_is_Z(card)) {
- chip = channel >> 2;
channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
-#ifdef CY_DEBUG_OPEN
- printk(KERN_DEBUG "cyc startup card %d, chip %d, channel %d, "
- "base_addr %p\n",
- card, chip, channel, base_addr);
-#endif
spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
+ cyy_writeb(info, CyCAR, channel);
- cy_writeb(base_addr + (CyRTPR << index),
+ cyy_writeb(info, CyRTPR,
(info->default_timeout ? info->default_timeout : 0x02));
/* 10ms rx timeout */
- cyy_issue_cmd(base_addr, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR,
- index);
-
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
- cy_writeb(base_addr + (CyMSVR1 << index), CyRTS);
- cy_writeb(base_addr + (CyMSVR2 << index), CyDTR);
-
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:startup raising DTR\n");
- printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
- readb(base_addr + (CyMSVR1 << index)),
- readb(base_addr + (CyMSVR2 << index)));
-#endif
+ cyy_issue_cmd(info, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR);
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) | CyRxData);
- info->port.flags |= ASYNC_INITIALIZED;
-
- if (info->port.tty)
- clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- info->breakon = info->breakoff = 0;
- memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
- info->idle_stats.in_use =
- info->idle_stats.recv_idle =
- info->idle_stats.xmit_idle = jiffies;
-
- spin_unlock_irqrestore(&card->card_lock, flags);
+ cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0);
+ cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyRxData);
} else {
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
- base_addr = card->base_addr;
-
- firm_id = base_addr + ID_ADDRESS;
if (!cyz_is_loaded(card))
return -ENODEV;
- zfw_ctrl = card->base_addr +
- (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
-
#ifdef CY_DEBUG_OPEN
printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
- "base_addr %p\n", card, channel, base_addr);
+ "base_addr %p\n", card, channel, card->base_addr);
#endif
spin_lock_irqsave(&card->card_lock, flags);
- cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
+ cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
#ifdef Z_WAKE
#ifdef CONFIG_CYZ_INTR
- cy_writel(&ch_ctrl[channel].intr_enable,
+ cy_writel(&ch_ctrl->intr_enable,
C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
#else
- cy_writel(&ch_ctrl[channel].intr_enable,
+ cy_writel(&ch_ctrl->intr_enable,
C_IN_IOCTLW | C_IN_MDCD);
#endif /* CONFIG_CYZ_INTR */
#else
#ifdef CONFIG_CYZ_INTR
- cy_writel(&ch_ctrl[channel].intr_enable,
+ cy_writel(&ch_ctrl->intr_enable,
C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
C_IN_RXNNDT | C_IN_MDCD);
#else
- cy_writel(&ch_ctrl[channel].intr_enable, C_IN_MDCD);
+ cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
#endif /* CONFIG_CYZ_INTR */
#endif /* Z_WAKE */
@@ -1968,32 +1388,22 @@ static int startup(struct cyclades_port *info)
/* set timeout !!! */
/* set RTS and DTR !!! */
- cy_writel(&ch_ctrl[channel].rs_control,
- readl(&ch_ctrl[channel].rs_control) | C_RS_RTS |
- C_RS_DTR);
- retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
- if (retval != 0) {
- printk(KERN_ERR "cyc:startup(3) retval on ttyC%d was "
- "%x\n", info->line, retval);
- }
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:startup raising Z DTR\n");
-#endif
+ tty_port_raise_dtr_rts(&info->port);
/* enable send, recv, modem !!! */
+ }
- info->port.flags |= ASYNC_INITIALIZED;
- if (info->port.tty)
- clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- info->breakon = info->breakoff = 0;
- memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
- info->idle_stats.in_use =
- info->idle_stats.recv_idle =
- info->idle_stats.xmit_idle = jiffies;
+ info->port.flags |= ASYNC_INITIALIZED;
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
+ clear_bit(TTY_IO_ERROR, &tty->flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ info->breakon = info->breakoff = 0;
+ memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
+ info->idle_stats.in_use =
+ info->idle_stats.recv_idle =
+ info->idle_stats.xmit_idle = jiffies;
+
+ spin_unlock_irqrestore(&card->card_lock, flags);
#ifdef CY_DEBUG_OPEN
printk(KERN_DEBUG "cyc startup done\n");
@@ -2002,28 +1412,20 @@ static int startup(struct cyclades_port *info)
errout:
spin_unlock_irqrestore(&card->card_lock, flags);
+ free_page(page);
return retval;
} /* startup */
static void start_xmit(struct cyclades_port *info)
{
- struct cyclades_card *card;
+ struct cyclades_card *card = info->card;
unsigned long flags;
- void __iomem *base_addr;
- int chip, channel, index;
+ int channel = info->line - card->first_line;
- card = info->card;
- channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
-
spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index), channel);
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) | CyTxRdy);
+ cyy_writeb(info, CyCAR, channel & 0x03);
+ cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
#ifdef CONFIG_CYZ_INTR
@@ -2046,12 +1448,11 @@ static void start_xmit(struct cyclades_port *info)
* This routine shuts down a serial port; interrupts are disabled,
* and DTR is dropped if the hangup on close termio flag is on.
*/
-static void shutdown(struct cyclades_port *info)
+static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
{
struct cyclades_card *card;
unsigned long flags;
- void __iomem *base_addr;
- int chip, channel, index;
+ int channel;
if (!(info->port.flags & ASYNC_INITIALIZED))
return;
@@ -2059,17 +1460,6 @@ static void shutdown(struct cyclades_port *info)
card = info->card;
channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
-
-#ifdef CY_DEBUG_OPEN
- printk(KERN_DEBUG "cyc shutdown Y card %d, chip %d, "
- "channel %d, base_addr %p\n",
- card, chip, channel, base_addr);
-#endif
-
spin_lock_irqsave(&card->card_lock, flags);
/* Clear delta_msr_wait queue to avoid mem leaks. */
@@ -2081,47 +1471,25 @@ static void shutdown(struct cyclades_port *info)
info->port.xmit_buf = NULL;
free_page((unsigned long)temp);
}
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
- if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
- cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS);
- cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR);
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc shutdown dropping DTR\n");
- printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
- readb(base_addr + (CyMSVR1 << index)),
- readb(base_addr + (CyMSVR2 << index)));
-#endif
- }
- cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index);
+ if (tty->termios->c_cflag & HUPCL)
+ cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
+
+ cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
/* it may be appropriate to clear _XMIT at
some later date (after testing)!!! */
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+ set_bit(TTY_IO_ERROR, &tty->flags);
info->port.flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
- int retval;
-
- base_addr = card->base_addr;
#ifdef CY_DEBUG_OPEN
printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
- "base_addr %p\n", card, channel, base_addr);
+ "base_addr %p\n", card, channel, card->base_addr);
#endif
- firm_id = base_addr + ID_ADDRESS;
if (!cyz_is_loaded(card))
return;
- zfw_ctrl = card->base_addr +
- (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
-
spin_lock_irqsave(&card->card_lock, flags);
if (info->port.xmit_buf) {
@@ -2131,23 +1499,10 @@ static void shutdown(struct cyclades_port *info)
free_page((unsigned long)temp);
}
- if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
- cy_writel(&ch_ctrl[channel].rs_control,
- (__u32)(readl(&ch_ctrl[channel].rs_control) &
- ~(C_RS_RTS | C_RS_DTR)));
- retval = cyz_issue_cmd(info->card, channel,
- C_CM_IOCTLM, 0L);
- if (retval != 0) {
- printk(KERN_ERR"cyc:shutdown retval on ttyC%d "
- "was %x\n", info->line, retval);
- }
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:shutdown dropping Z DTR\n");
-#endif
- }
+ if (tty->termios->c_cflag & HUPCL)
+ tty_port_lower_dtr_rts(&info->port);
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+ set_bit(TTY_IO_ERROR, &tty->flags);
info->port.flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&card->card_lock, flags);
@@ -2164,199 +1519,6 @@ static void shutdown(struct cyclades_port *info)
* ------------------------------------------------------------
*/
-static int
-block_til_ready(struct tty_struct *tty, struct file *filp,
- struct cyclades_port *info)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct cyclades_card *cinfo;
- unsigned long flags;
- int chip, channel, index;
- int retval;
- void __iomem *base_addr;
-
- cinfo = info->card;
- channel = info->line - cinfo->first_line;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
- wait_event_interruptible(info->port.close_wait,
- !(info->port.flags & ASYNC_CLOSING));
- return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
- }
-
- /*
- * If non-blocking mode is set, then make the check up front
- * and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- info->port.flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
-
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->port.count is dropped by one, so that
- * cy_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->port.open_wait, &wait);
-#ifdef CY_DEBUG_OPEN
- printk(KERN_DEBUG "cyc block_til_ready before block: ttyC%d, "
- "count = %d\n", info->line, info->port.count);
-#endif
- spin_lock_irqsave(&cinfo->card_lock, flags);
- if (!tty_hung_up_p(filp))
- info->port.count--;
- spin_unlock_irqrestore(&cinfo->card_lock, flags);
-#ifdef CY_DEBUG_COUNT
- printk(KERN_DEBUG "cyc block_til_ready: (%d): decrementing count to "
- "%d\n", current->pid, info->port.count);
-#endif
- info->port.blocked_open++;
-
- if (!cy_is_Z(cinfo)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = cinfo->bus_index;
- base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
-
- while (1) {
- spin_lock_irqsave(&cinfo->card_lock, flags);
- if ((tty->termios->c_cflag & CBAUD)) {
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) channel);
- cy_writeb(base_addr + (CyMSVR1 << index),
- CyRTS);
- cy_writeb(base_addr + (CyMSVR2 << index),
- CyDTR);
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:block_til_ready raising "
- "DTR\n");
- printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
- readb(base_addr + (CyMSVR1 << index)),
- readb(base_addr + (CyMSVR2 << index)));
-#endif
- }
- spin_unlock_irqrestore(&cinfo->card_lock, flags);
-
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(info->port.flags & ASYNC_INITIALIZED)) {
- retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
- break;
- }
-
- spin_lock_irqsave(&cinfo->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) channel);
- if (!(info->port.flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
- (readb(base_addr +
- (CyMSVR1 << index)) & CyDCD))) {
- spin_unlock_irqrestore(&cinfo->card_lock, flags);
- break;
- }
- spin_unlock_irqrestore(&cinfo->card_lock, flags);
-
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-#ifdef CY_DEBUG_OPEN
- printk(KERN_DEBUG "cyc block_til_ready blocking: "
- "ttyC%d, count = %d\n",
- info->line, info->port.count);
-#endif
- schedule();
- }
- } else {
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
-
- base_addr = cinfo->base_addr;
- firm_id = base_addr + ID_ADDRESS;
- if (!cyz_is_loaded(cinfo)) {
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&info->port.open_wait, &wait);
- return -EINVAL;
- }
-
- zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr)
- & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
-
- while (1) {
- if ((tty->termios->c_cflag & CBAUD)) {
- cy_writel(&ch_ctrl[channel].rs_control,
- readl(&ch_ctrl[channel].rs_control) |
- C_RS_RTS | C_RS_DTR);
- retval = cyz_issue_cmd(cinfo,
- channel, C_CM_IOCTLM, 0L);
- if (retval != 0) {
- printk(KERN_ERR "cyc:block_til_ready "
- "retval on ttyC%d was %x\n",
- info->line, retval);
- }
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:block_til_ready raising "
- "Z DTR\n");
-#endif
- }
-
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(info->port.flags & ASYNC_INITIALIZED)) {
- retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
- break;
- }
- if (!(info->port.flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
- (readl(&ch_ctrl[channel].rs_status) &
- C_RS_DCD))) {
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-#ifdef CY_DEBUG_OPEN
- printk(KERN_DEBUG "cyc block_til_ready blocking: "
- "ttyC%d, count = %d\n",
- info->line, info->port.count);
-#endif
- schedule();
- }
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&info->port.open_wait, &wait);
- if (!tty_hung_up_p(filp)) {
- info->port.count++;
-#ifdef CY_DEBUG_COUNT
- printk(KERN_DEBUG "cyc:block_til_ready (%d): incrementing "
- "count to %d\n", current->pid, info->port.count);
-#endif
- }
- info->port.blocked_open--;
-#ifdef CY_DEBUG_OPEN
- printk(KERN_DEBUG "cyc:block_til_ready after blocking: ttyC%d, "
- "count = %d\n", info->line, info->port.count);
-#endif
- if (retval)
- return retval;
- info->port.flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
-} /* block_til_ready */
-
/*
* This routine is called whenever a serial port is opened. It
* performs the serial-specific initialization for the tty structure.
@@ -2435,7 +1597,6 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
#endif
tty->driver_data = info;
- info->port.tty = tty;
if (serial_paranoia_check(info, tty->name, "cy_open"))
return -ENODEV;
@@ -2461,11 +1622,11 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
/*
* Start up serial port
*/
- retval = startup(info);
+ retval = cy_startup(info, tty);
if (retval)
return retval;
- retval = block_til_ready(tty, filp, info);
+ retval = tty_port_block_til_ready(&info->port, tty, filp);
if (retval) {
#ifdef CY_DEBUG_OPEN
printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
@@ -2475,6 +1636,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
}
info->throttle = 0;
+ tty_port_tty_set(&info->port, tty);
#ifdef CY_DEBUG_OPEN
printk(KERN_DEBUG "cyc:cy_open done\n");
@@ -2489,8 +1651,6 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
{
struct cyclades_card *card;
struct cyclades_port *info = tty->driver_data;
- void __iomem *base_addr;
- int chip, channel, index;
unsigned long orig_jiffies;
int char_time;
@@ -2534,13 +1694,8 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
timeout, char_time, jiffies);
#endif
card = info->card;
- channel = (info->line) - (card->first_line);
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
- while (readb(base_addr + (CySRER << index)) & CyTxRdy) {
+ while (cyy_readb(info, CySRER) & CyTxRdy) {
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies);
#endif
@@ -2602,75 +1757,23 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
struct cyclades_port *info = tty->driver_data;
struct cyclades_card *card;
unsigned long flags;
-
-#ifdef CY_DEBUG_OTHER
- printk(KERN_DEBUG "cyc:cy_close ttyC%d\n", info->line);
-#endif
+ int channel;
if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
return;
card = info->card;
- spin_lock_irqsave(&card->card_lock, flags);
- /* If the TTY is being hung up, nothing to do */
- if (tty_hung_up_p(filp)) {
- spin_unlock_irqrestore(&card->card_lock, flags);
- return;
- }
-#ifdef CY_DEBUG_OPEN
- printk(KERN_DEBUG "cyc:cy_close ttyC%d, count = %d\n", info->line,
- info->port.count);
-#endif
- if ((tty->count == 1) && (info->port.count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk(KERN_ERR "cyc:cy_close: bad serial port count; "
- "tty->count is 1, info->port.count is %d\n", info->port.count);
- info->port.count = 1;
- }
-#ifdef CY_DEBUG_COUNT
- printk(KERN_DEBUG "cyc:cy_close at (%d): decrementing count to %d\n",
- current->pid, info->port.count - 1);
-#endif
- if (--info->port.count < 0) {
-#ifdef CY_DEBUG_COUNT
- printk(KERN_DEBUG "cyc:cyc_close setting count to 0\n");
-#endif
- info->port.count = 0;
- }
- if (info->port.count) {
- spin_unlock_irqrestore(&card->card_lock, flags);
+ if (!tty_port_close_start(&info->port, tty, filp))
return;
- }
- info->port.flags |= ASYNC_CLOSING;
-
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- spin_unlock_irqrestore(&card->card_lock, flags);
- if (info->port.closing_wait != CY_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, info->port.closing_wait);
+ channel = info->line - card->first_line;
spin_lock_irqsave(&card->card_lock, flags);
if (!cy_is_Z(card)) {
- int channel = info->line - card->first_line;
- int index = card->bus_index;
- void __iomem *base_addr = card->base_addr +
- (cy_chip_offset[channel >> 2] << index);
/* Stop accepting input */
- channel &= 0x03;
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) & ~CyRxData);
+ cyy_writeb(info, CyCAR, channel & 0x03);
+ cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
if (info->port.flags & ASYNC_INITIALIZED) {
/* Waiting for on-board buffers to be empty before
closing the port */
@@ -2682,15 +1785,10 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
#ifdef Z_WAKE
/* Waiting for on-board buffers to be empty before closing
the port */
- void __iomem *base_addr = card->base_addr;
- struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS;
- struct ZFW_CTRL __iomem *zfw_ctrl =
- base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl;
- int channel = info->line - card->first_line;
+ struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
int retval;
- if (readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
+ if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
if (retval != 0) {
printk(KERN_DEBUG "cyc:cy_close retval on "
@@ -2704,30 +1802,12 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
}
spin_unlock_irqrestore(&card->card_lock, flags);
- shutdown(info);
+ cy_shutdown(info, tty);
cy_flush_buffer(tty);
- tty_ldisc_flush(tty);
- spin_lock_irqsave(&card->card_lock, flags);
- tty->closing = 0;
- info->port.tty = NULL;
- if (info->port.blocked_open) {
- spin_unlock_irqrestore(&card->card_lock, flags);
- if (info->port.close_delay) {
- msleep_interruptible(jiffies_to_msecs
- (info->port.close_delay));
- }
- wake_up_interruptible(&info->port.open_wait);
- spin_lock_irqsave(&card->card_lock, flags);
- }
- info->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
- wake_up_interruptible(&info->port.close_wait);
-
-#ifdef CY_DEBUG_OTHER
- printk(KERN_DEBUG "cyc:cy_close done\n");
-#endif
+ tty_port_tty_set(&info->port, NULL);
- spin_unlock_irqrestore(&card->card_lock, flags);
+ tty_port_close_end(&info->port, tty);
} /* cy_close */
/* This routine gets called when tty_write has put something into
@@ -2870,18 +1950,13 @@ static int cy_write_room(struct tty_struct *tty)
static int cy_chars_in_buffer(struct tty_struct *tty)
{
- struct cyclades_card *card;
struct cyclades_port *info = tty->driver_data;
- int channel;
if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
return 0;
- card = info->card;
- channel = (info->line) - (card->first_line);
-
#ifdef Z_EXT_CHARS_IN_BUFFER
- if (!cy_is_Z(card)) {
+ if (!cy_is_Z(info->card)) {
#endif /* Z_EXT_CHARS_IN_BUFFER */
#ifdef CY_DEBUG_IO
printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
@@ -2890,20 +1965,11 @@ static int cy_chars_in_buffer(struct tty_struct *tty)
return info->xmit_cnt;
#ifdef Z_EXT_CHARS_IN_BUFFER
} else {
- static struct FIRM_ID *firm_id;
- static struct ZFW_CTRL *zfw_ctrl;
- static struct CH_CTRL *ch_ctrl;
- static struct BUF_CTRL *buf_ctrl;
+ struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
int char_count;
__u32 tx_put, tx_get, tx_bufsize;
lock_kernel();
- firm_id = card->base_addr + ID_ADDRESS;
- zfw_ctrl = card->base_addr +
- (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
- buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
-
tx_get = readl(&buf_ctrl->tx_get);
tx_put = readl(&buf_ctrl->tx_put);
tx_bufsize = readl(&buf_ctrl->tx_bufsize);
@@ -2956,48 +2022,44 @@ static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
* This routine finds or computes the various line characteristics.
* It used to be called config_setup
*/
-static void set_line_char(struct cyclades_port *info)
+static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
{
struct cyclades_card *card;
unsigned long flags;
- void __iomem *base_addr;
- int chip, channel, index;
+ int channel;
unsigned cflag, iflag;
int baud, baud_rate = 0;
int i;
- if (!info->port.tty || !info->port.tty->termios)
+ if (!tty->termios) /* XXX can this happen at all? */
return;
if (info->line == -1)
return;
- cflag = info->port.tty->termios->c_cflag;
- iflag = info->port.tty->termios->c_iflag;
+ cflag = tty->termios->c_cflag;
+ iflag = tty->termios->c_iflag;
/*
* Set up the tty->alt_speed kludge
*/
- if (info->port.tty) {
- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- info->port.tty->alt_speed = 57600;
- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- info->port.tty->alt_speed = 115200;
- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
- info->port.tty->alt_speed = 230400;
- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
- info->port.tty->alt_speed = 460800;
- }
+ if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ tty->alt_speed = 57600;
+ if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ tty->alt_speed = 115200;
+ if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ tty->alt_speed = 230400;
+ if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ tty->alt_speed = 460800;
card = info->card;
channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
-
- index = card->bus_index;
+ u32 cflags;
/* baud rate */
- baud = tty_get_baud_rate(info->port.tty);
+ baud = tty_get_baud_rate(tty);
if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
ASYNC_SPD_CUST) {
if (info->custom_divisor)
@@ -3106,124 +2168,68 @@ static void set_line_char(struct cyclades_port *info)
cable. Contact Marcio Saito for details.
***********************************************/
- chip = channel >> 2;
channel &= 0x03;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
+ cyy_writeb(info, CyCAR, channel);
/* tx and rx baud rate */
- cy_writeb(base_addr + (CyTCOR << index), info->tco);
- cy_writeb(base_addr + (CyTBPR << index), info->tbpr);
- cy_writeb(base_addr + (CyRCOR << index), info->rco);
- cy_writeb(base_addr + (CyRBPR << index), info->rbpr);
+ cyy_writeb(info, CyTCOR, info->tco);
+ cyy_writeb(info, CyTBPR, info->tbpr);
+ cyy_writeb(info, CyRCOR, info->rco);
+ cyy_writeb(info, CyRBPR, info->rbpr);
/* set line characteristics according configuration */
- cy_writeb(base_addr + (CySCHR1 << index),
- START_CHAR(info->port.tty));
- cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(info->port.tty));
- cy_writeb(base_addr + (CyCOR1 << index), info->cor1);
- cy_writeb(base_addr + (CyCOR2 << index), info->cor2);
- cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
- cy_writeb(base_addr + (CyCOR4 << index), info->cor4);
- cy_writeb(base_addr + (CyCOR5 << index), info->cor5);
+ cyy_writeb(info, CySCHR1, START_CHAR(tty));
+ cyy_writeb(info, CySCHR2, STOP_CHAR(tty));
+ cyy_writeb(info, CyCOR1, info->cor1);
+ cyy_writeb(info, CyCOR2, info->cor2);
+ cyy_writeb(info, CyCOR3, info->cor3);
+ cyy_writeb(info, CyCOR4, info->cor4);
+ cyy_writeb(info, CyCOR5, info->cor5);
- cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
- CyCOR3ch, index);
+ cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
+ CyCOR3ch);
/* !!! Is this needed? */
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
- cy_writeb(base_addr + (CyRTPR << index),
+ cyy_writeb(info, CyCAR, channel);
+ cyy_writeb(info, CyRTPR,
(info->default_timeout ? info->default_timeout : 0x02));
/* 10ms rx timeout */
- if (C_CLOCAL(info->port.tty)) {
- /* without modem intr */
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) | CyMdmCh);
- /* act on 1->0 modem transitions */
- if ((cflag & CRTSCTS) && info->rflow) {
- cy_writeb(base_addr + (CyMCOR1 << index),
- (CyCTS | rflow_thr[i]));
- } else {
- cy_writeb(base_addr + (CyMCOR1 << index),
- CyCTS);
- }
- /* act on 0->1 modem transitions */
- cy_writeb(base_addr + (CyMCOR2 << index), CyCTS);
- } else {
- /* without modem intr */
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr +
- (CySRER << index)) | CyMdmCh);
- /* act on 1->0 modem transitions */
- if ((cflag & CRTSCTS) && info->rflow) {
- cy_writeb(base_addr + (CyMCOR1 << index),
- (CyDSR | CyCTS | CyRI | CyDCD |
- rflow_thr[i]));
- } else {
- cy_writeb(base_addr + (CyMCOR1 << index),
- CyDSR | CyCTS | CyRI | CyDCD);
- }
- /* act on 0->1 modem transitions */
- cy_writeb(base_addr + (CyMCOR2 << index),
- CyDSR | CyCTS | CyRI | CyDCD);
- }
+ cflags = CyCTS;
+ if (!C_CLOCAL(tty))
+ cflags |= CyDSR | CyRI | CyDCD;
+ /* without modem intr */
+ cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh);
+ /* act on 1->0 modem transitions */
+ if ((cflag & CRTSCTS) && info->rflow)
+ cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]);
+ else
+ cyy_writeb(info, CyMCOR1, cflags);
+ /* act on 0->1 modem transitions */
+ cyy_writeb(info, CyMCOR2, cflags);
- if (i == 0) { /* baud rate is zero, turn off line */
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr + (CyMSVR1 << index),
- ~CyRTS);
- } else {
- cy_writeb(base_addr + (CyMSVR2 << index),
- ~CyDTR);
- }
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:set_line_char dropping DTR\n");
- printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
- readb(base_addr + (CyMSVR1 << index)),
- readb(base_addr + (CyMSVR2 << index)));
-#endif
- } else {
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr + (CyMSVR1 << index),
- CyRTS);
- } else {
- cy_writeb(base_addr + (CyMSVR2 << index),
- CyDTR);
- }
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:set_line_char raising DTR\n");
- printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
- readb(base_addr + (CyMSVR1 << index)),
- readb(base_addr + (CyMSVR2 << index)));
-#endif
- }
+ if (i == 0) /* baud rate is zero, turn off line */
+ cyy_change_rts_dtr(info, 0, TIOCM_DTR);
+ else
+ cyy_change_rts_dtr(info, TIOCM_DTR, 0);
- if (info->port.tty)
- clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+ clear_bit(TTY_IO_ERROR, &tty->flags);
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
__u32 sw_flow;
int retval;
- firm_id = card->base_addr + ID_ADDRESS;
if (!cyz_is_loaded(card))
return;
- zfw_ctrl = card->base_addr +
- (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
-
/* baud rate */
- baud = tty_get_baud_rate(info->port.tty);
+ baud = tty_get_baud_rate(tty);
if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
ASYNC_SPD_CUST) {
if (info->custom_divisor)
@@ -3334,45 +2340,38 @@ static void set_line_char(struct cyclades_port *info)
"was %x\n", info->line, retval);
}
- if (info->port.tty)
- clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+ clear_bit(TTY_IO_ERROR, &tty->flags);
}
} /* set_line_char */
-static int
-get_serial_info(struct cyclades_port *info,
+static int cy_get_serial_info(struct cyclades_port *info,
struct serial_struct __user *retinfo)
{
- struct serial_struct tmp;
struct cyclades_card *cinfo = info->card;
-
- if (!retinfo)
- return -EFAULT;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->line;
- tmp.port = (info->card - cy_card) * 0x100 + info->line -
- cinfo->first_line;
- tmp.irq = cinfo->irq;
- tmp.flags = info->port.flags;
- tmp.close_delay = info->port.close_delay;
- tmp.closing_wait = info->port.closing_wait;
- tmp.baud_base = info->baud;
- tmp.custom_divisor = info->custom_divisor;
- tmp.hub6 = 0; /*!!! */
+ struct serial_struct tmp = {
+ .type = info->type,
+ .line = info->line,
+ .port = (info->card - cy_card) * 0x100 + info->line -
+ cinfo->first_line,
+ .irq = cinfo->irq,
+ .flags = info->port.flags,
+ .close_delay = info->port.close_delay,
+ .closing_wait = info->port.closing_wait,
+ .baud_base = info->baud,
+ .custom_divisor = info->custom_divisor,
+ .hub6 = 0, /*!!! */
+ };
return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
-} /* get_serial_info */
+}
static int
-set_serial_info(struct cyclades_port *info,
+cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
struct serial_struct __user *new_info)
{
struct serial_struct new_serial;
- struct cyclades_port old_info;
if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
return -EFAULT;
- old_info = *info;
if (!capable(CAP_SYS_ADMIN)) {
if (new_serial.close_delay != info->port.close_delay ||
@@ -3402,10 +2401,10 @@ set_serial_info(struct cyclades_port *info,
check_and_exit:
if (info->port.flags & ASYNC_INITIALIZED) {
- set_line_char(info);
+ cy_set_line_char(info, tty);
return 0;
} else {
- return startup(info);
+ return cy_startup(info, tty);
}
} /* set_serial_info */
@@ -3421,24 +2420,14 @@ check_and_exit:
*/
static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
{
- struct cyclades_card *card;
- int chip, channel, index;
- unsigned char status;
+ struct cyclades_card *card = info->card;
unsigned int result;
unsigned long flags;
- void __iomem *base_addr;
+ u8 status;
- card = info->card;
- channel = (info->line) - (card->first_line);
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
-
spin_lock_irqsave(&card->card_lock, flags);
- status = readb(base_addr + (CySRER << index)) &
- (CyTxRdy | CyTxMpty);
+ status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty);
spin_unlock_irqrestore(&card->card_lock, flags);
result = (status ? 0 : TIOCSER_TEMT);
} else {
@@ -3452,34 +2441,23 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
{
struct cyclades_port *info = tty->driver_data;
struct cyclades_card *card;
- int chip, channel, index;
- void __iomem *base_addr;
- unsigned long flags;
- unsigned char status;
- unsigned long lstatus;
- unsigned int result;
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
+ int result;
if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
- lock_kernel();
-
card = info->card;
- channel = info->line - card->first_line;
+
+ lock_kernel();
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
+ unsigned long flags;
+ int channel = info->line - card->first_line;
+ u8 status;
spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
- status = readb(base_addr + (CyMSVR1 << index));
- status |= readb(base_addr + (CyMSVR2 << index));
+ cyy_writeb(info, CyCAR, channel & 0x03);
+ status = cyy_readb(info, CyMSVR1);
+ status |= cyy_readb(info, CyMSVR2);
spin_unlock_irqrestore(&card->card_lock, flags);
if (info->rtsdtr_inv) {
@@ -3494,27 +2472,22 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
((status & CyDSR) ? TIOCM_DSR : 0) |
((status & CyCTS) ? TIOCM_CTS : 0);
} else {
- base_addr = card->base_addr;
- firm_id = card->base_addr + ID_ADDRESS;
- if (cyz_is_loaded(card)) {
- zfw_ctrl = card->base_addr +
- (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
- lstatus = readl(&ch_ctrl[channel].rs_status);
- result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
- ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
- ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
- ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
- ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
- ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
- } else {
- result = 0;
- unlock_kernel();
- return -ENODEV;
+ u32 lstatus;
+
+ if (!cyz_is_loaded(card)) {
+ result = -ENODEV;
+ goto end;
}
+ lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
+ result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
+ ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
+ ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
+ ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
+ ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
+ ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
}
+end:
unlock_kernel();
return result;
} /* cy_tiomget */
@@ -3525,150 +2498,53 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
{
struct cyclades_port *info = tty->driver_data;
struct cyclades_card *card;
- int chip, channel, index;
- void __iomem *base_addr;
unsigned long flags;
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
- int retval;
if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
card = info->card;
- channel = (info->line) - (card->first_line);
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
+ spin_lock_irqsave(&card->card_lock, flags);
+ cyy_change_rts_dtr(info, set, clear);
+ spin_unlock_irqrestore(&card->card_lock, flags);
+ } else {
+ struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
+ int retval, channel = info->line - card->first_line;
+ u32 rs;
- if (set & TIOCM_RTS) {
- spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr + (CyMSVR2 << index),
- CyDTR);
- } else {
- cy_writeb(base_addr + (CyMSVR1 << index),
- CyRTS);
- }
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
- if (clear & TIOCM_RTS) {
- spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr + (CyMSVR2 << index),
- ~CyDTR);
- } else {
- cy_writeb(base_addr + (CyMSVR1 << index),
- ~CyRTS);
- }
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
+ if (!cyz_is_loaded(card))
+ return -ENODEV;
+
+ spin_lock_irqsave(&card->card_lock, flags);
+ rs = readl(&ch_ctrl->rs_control);
+ if (set & TIOCM_RTS)
+ rs |= C_RS_RTS;
+ if (clear & TIOCM_RTS)
+ rs &= ~C_RS_RTS;
if (set & TIOCM_DTR) {
- spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr + (CyMSVR1 << index),
- CyRTS);
- } else {
- cy_writeb(base_addr + (CyMSVR2 << index),
- CyDTR);
- }
+ rs |= C_RS_DTR;
#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
- printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
- readb(base_addr + (CyMSVR1 << index)),
- readb(base_addr + (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n");
#endif
- spin_unlock_irqrestore(&card->card_lock, flags);
}
if (clear & TIOCM_DTR) {
- spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr + (CyMSVR1 << index),
- ~CyRTS);
- } else {
- cy_writeb(base_addr + (CyMSVR2 << index),
- ~CyDTR);
- }
-
+ rs &= ~C_RS_DTR;
#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
- printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
- readb(base_addr + (CyMSVR1 << index)),
- readb(base_addr + (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc:set_modem_info clearing "
+ "Z DTR\n");
#endif
- spin_unlock_irqrestore(&card->card_lock, flags);
}
- } else {
- base_addr = card->base_addr;
-
- firm_id = card->base_addr + ID_ADDRESS;
- if (cyz_is_loaded(card)) {
- zfw_ctrl = card->base_addr +
- (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
-
- if (set & TIOCM_RTS) {
- spin_lock_irqsave(&card->card_lock, flags);
- cy_writel(&ch_ctrl[channel].rs_control,
- readl(&ch_ctrl[channel].rs_control) |
- C_RS_RTS);
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
- if (clear & TIOCM_RTS) {
- spin_lock_irqsave(&card->card_lock, flags);
- cy_writel(&ch_ctrl[channel].rs_control,
- readl(&ch_ctrl[channel].rs_control) &
- ~C_RS_RTS);
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
- if (set & TIOCM_DTR) {
- spin_lock_irqsave(&card->card_lock, flags);
- cy_writel(&ch_ctrl[channel].rs_control,
- readl(&ch_ctrl[channel].rs_control) |
- C_RS_DTR);
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:set_modem_info raising "
- "Z DTR\n");
-#endif
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
- if (clear & TIOCM_DTR) {
- spin_lock_irqsave(&card->card_lock, flags);
- cy_writel(&ch_ctrl[channel].rs_control,
- readl(&ch_ctrl[channel].rs_control) &
- ~C_RS_DTR);
-#ifdef CY_DEBUG_DTR
- printk(KERN_DEBUG "cyc:set_modem_info clearing "
- "Z DTR\n");
-#endif
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
- } else {
- return -ENODEV;
- }
- spin_lock_irqsave(&card->card_lock, flags);
+ cy_writel(&ch_ctrl->rs_control, rs);
retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
+ spin_unlock_irqrestore(&card->card_lock, flags);
if (retval != 0) {
printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
"was %x\n", info->line, retval);
}
- spin_unlock_irqrestore(&card->card_lock, flags);
}
return 0;
-} /* cy_tiocmset */
+}
/*
* cy_break() --- routine which turns the break handling on or off
@@ -3733,41 +2609,18 @@ static int cy_break(struct tty_struct *tty, int break_state)
return retval;
} /* cy_break */
-static int get_mon_info(struct cyclades_port *info,
- struct cyclades_monitor __user *mon)
-{
-
- if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
- return -EFAULT;
- info->mon.int_count = 0;
- info->mon.char_count = 0;
- info->mon.char_max = 0;
- info->mon.char_last = 0;
- return 0;
-} /* get_mon_info */
-
static int set_threshold(struct cyclades_port *info, unsigned long value)
{
- struct cyclades_card *card;
- void __iomem *base_addr;
- int channel, chip, index;
+ struct cyclades_card *card = info->card;
unsigned long flags;
- card = info->card;
- channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr =
- card->base_addr + (cy_chip_offset[chip] << index);
-
info->cor3 &= ~CyREC_FIFO;
info->cor3 |= value & CyREC_FIFO;
spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
- cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index);
+ cyy_writeb(info, CyCOR3, info->cor3);
+ cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch);
spin_unlock_irqrestore(&card->card_lock, flags);
}
return 0;
@@ -3776,55 +2629,23 @@ static int set_threshold(struct cyclades_port *info, unsigned long value)
static int get_threshold(struct cyclades_port *info,
unsigned long __user *value)
{
- struct cyclades_card *card;
- void __iomem *base_addr;
- int channel, chip, index;
- unsigned long tmp;
+ struct cyclades_card *card = info->card;
- card = info->card;
- channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
-
- tmp = readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
+ u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO;
return put_user(tmp, value);
}
return 0;
} /* get_threshold */
-static int set_default_threshold(struct cyclades_port *info,
- unsigned long value)
-{
- info->default_threshold = value & 0x0f;
- return 0;
-} /* set_default_threshold */
-
-static int get_default_threshold(struct cyclades_port *info,
- unsigned long __user *value)
-{
- return put_user(info->default_threshold, value);
-} /* get_default_threshold */
-
static int set_timeout(struct cyclades_port *info, unsigned long value)
{
- struct cyclades_card *card;
- void __iomem *base_addr;
- int channel, chip, index;
+ struct cyclades_card *card = info->card;
unsigned long flags;
- card = info->card;
- channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
-
spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyRTPR << index), value & 0xff);
+ cyy_writeb(info, CyRTPR, value & 0xff);
spin_unlock_irqrestore(&card->card_lock, flags);
}
return 0;
@@ -3833,36 +2654,35 @@ static int set_timeout(struct cyclades_port *info, unsigned long value)
static int get_timeout(struct cyclades_port *info,
unsigned long __user *value)
{
- struct cyclades_card *card;
- void __iomem *base_addr;
- int channel, chip, index;
- unsigned long tmp;
+ struct cyclades_card *card = info->card;
- card = info->card;
- channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr + (cy_chip_offset[chip] << index);
-
- tmp = readb(base_addr + (CyRTPR << index));
+ u8 tmp = cyy_readb(info, CyRTPR);
return put_user(tmp, value);
}
return 0;
} /* get_timeout */
-static int set_default_timeout(struct cyclades_port *info, unsigned long value)
+static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
+ struct cyclades_icount *cprev)
{
- info->default_timeout = value & 0xff;
- return 0;
-} /* set_default_timeout */
+ struct cyclades_icount cnow;
+ unsigned long flags;
+ int ret;
-static int get_default_timeout(struct cyclades_port *info,
- unsigned long __user *value)
-{
- return put_user(info->default_timeout, value);
-} /* get_default_timeout */
+ spin_lock_irqsave(&info->card->card_lock, flags);
+ cnow = info->icount; /* atomic copy */
+ spin_unlock_irqrestore(&info->card->card_lock, flags);
+
+ ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
+
+ *cprev = cnow;
+
+ return ret;
+}
/*
* This routine allows the tty driver to implement device-
@@ -3874,8 +2694,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct cyclades_port *info = tty->driver_data;
- struct cyclades_icount cprev, cnow; /* kernel counter temps */
- struct serial_icounter_struct __user *p_cuser; /* user space */
+ struct cyclades_icount cnow; /* kernel counter temps */
int ret_val = 0;
unsigned long flags;
void __user *argp = (void __user *)arg;
@@ -3891,7 +2710,11 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
switch (cmd) {
case CYGETMON:
- ret_val = get_mon_info(info, argp);
+ if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
+ ret_val = -EFAULT;
+ break;
+ }
+ memset(&info->mon, 0, sizeof(info->mon));
break;
case CYGETTHRESH:
ret_val = get_threshold(info, argp);
@@ -3900,10 +2723,11 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
ret_val = set_threshold(info, arg);
break;
case CYGETDEFTHRESH:
- ret_val = get_default_threshold(info, argp);
+ ret_val = put_user(info->default_threshold,
+ (unsigned long __user *)argp);
break;
case CYSETDEFTHRESH:
- ret_val = set_default_threshold(info, arg);
+ info->default_threshold = arg & 0x0f;
break;
case CYGETTIMEOUT:
ret_val = get_timeout(info, argp);
@@ -3912,21 +2736,20 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
ret_val = set_timeout(info, arg);
break;
case CYGETDEFTIMEOUT:
- ret_val = get_default_timeout(info, argp);
+ ret_val = put_user(info->default_timeout,
+ (unsigned long __user *)argp);
break;
case CYSETDEFTIMEOUT:
- ret_val = set_default_timeout(info, arg);
+ info->default_timeout = arg & 0xff;
break;
case CYSETRFLOW:
info->rflow = (int)arg;
- ret_val = 0;
break;
case CYGETRFLOW:
ret_val = info->rflow;
break;
case CYSETRTSDTR_INV:
info->rtsdtr_inv = (int)arg;
- ret_val = 0;
break;
case CYGETRTSDTR_INV:
ret_val = info->rtsdtr_inv;
@@ -3937,7 +2760,6 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
#ifndef CONFIG_CYZ_INTR
case CYZSETPOLLCYCLE:
cyz_polling_cycle = (arg * HZ) / 1000;
- ret_val = 0;
break;
case CYZGETPOLLCYCLE:
ret_val = (cyz_polling_cycle * 1000) / HZ;
@@ -3945,16 +2767,15 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
#endif /* CONFIG_CYZ_INTR */
case CYSETWAIT:
info->port.closing_wait = (unsigned short)arg * HZ / 100;
- ret_val = 0;
break;
case CYGETWAIT:
ret_val = info->port.closing_wait / (HZ / 100);
break;
case TIOCGSERIAL:
- ret_val = get_serial_info(info, argp);
+ ret_val = cy_get_serial_info(info, argp);
break;
case TIOCSSERIAL:
- ret_val = set_serial_info(info, argp);
+ ret_val = cy_set_serial_info(info, tty, argp);
break;
case TIOCSERGETLSR: /* Get line status register */
ret_val = get_lsr_info(info, argp);
@@ -3970,17 +2791,8 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
/* note the counters on entry */
cnow = info->icount;
spin_unlock_irqrestore(&info->card->card_lock, flags);
- ret_val = wait_event_interruptible(info->delta_msr_wait, ({
- cprev = cnow;
- spin_lock_irqsave(&info->card->card_lock, flags);
- cnow = info->icount; /* atomic copy */
- spin_unlock_irqrestore(&info->card->card_lock, flags);
-
- ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts));
- }));
+ ret_val = wait_event_interruptible(info->delta_msr_wait,
+ cy_cflags_changed(info, arg, &cnow));
break;
/*
@@ -3989,46 +2801,29 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
* NB: both 1->0 and 0->1 transitions are counted except for
* RI where only 0->1 is counted.
*/
- case TIOCGICOUNT:
+ case TIOCGICOUNT: {
+ struct serial_icounter_struct sic = { };
+
spin_lock_irqsave(&info->card->card_lock, flags);
cnow = info->icount;
spin_unlock_irqrestore(&info->card->card_lock, flags);
- p_cuser = argp;
- ret_val = put_user(cnow.cts, &p_cuser->cts);
- if (ret_val)
- break;
- ret_val = put_user(cnow.dsr, &p_cuser->dsr);
- if (ret_val)
- break;
- ret_val = put_user(cnow.rng, &p_cuser->rng);
- if (ret_val)
- break;
- ret_val = put_user(cnow.dcd, &p_cuser->dcd);
- if (ret_val)
- break;
- ret_val = put_user(cnow.rx, &p_cuser->rx);
- if (ret_val)
- break;
- ret_val = put_user(cnow.tx, &p_cuser->tx);
- if (ret_val)
- break;
- ret_val = put_user(cnow.frame, &p_cuser->frame);
- if (ret_val)
- break;
- ret_val = put_user(cnow.overrun, &p_cuser->overrun);
- if (ret_val)
- break;
- ret_val = put_user(cnow.parity, &p_cuser->parity);
- if (ret_val)
- break;
- ret_val = put_user(cnow.brk, &p_cuser->brk);
- if (ret_val)
- break;
- ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
- if (ret_val)
- break;
- ret_val = 0;
+
+ sic.cts = cnow.cts;
+ sic.dsr = cnow.dsr;
+ sic.rng = cnow.rng;
+ sic.dcd = cnow.dcd;
+ sic.rx = cnow.rx;
+ sic.tx = cnow.tx;
+ sic.frame = cnow.frame;
+ sic.overrun = cnow.overrun;
+ sic.parity = cnow.parity;
+ sic.brk = cnow.brk;
+ sic.buf_overrun = cnow.buf_overrun;
+
+ if (copy_to_user(argp, &sic, sizeof(sic)))
+ ret_val = -EFAULT;
break;
+ }
default:
ret_val = -ENOIOCTLCMD;
}
@@ -4054,7 +2849,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
#endif
- set_line_char(info);
+ cy_set_line_char(info, tty);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
@@ -4111,8 +2906,6 @@ static void cy_throttle(struct tty_struct *tty)
struct cyclades_port *info = tty->driver_data;
struct cyclades_card *card;
unsigned long flags;
- void __iomem *base_addr;
- int chip, channel, index;
#ifdef CY_DEBUG_THROTTLE
char buf[64];
@@ -4134,24 +2927,9 @@ static void cy_throttle(struct tty_struct *tty)
}
if (tty->termios->c_cflag & CRTSCTS) {
- channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr +
- (cy_chip_offset[chip] << index);
-
spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr + (CyMSVR2 << index),
- ~CyDTR);
- } else {
- cy_writeb(base_addr + (CyMSVR1 << index),
- ~CyRTS);
- }
+ cyy_change_rts_dtr(info, 0, TIOCM_RTS);
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
info->throttle = 1;
@@ -4169,8 +2947,6 @@ static void cy_unthrottle(struct tty_struct *tty)
struct cyclades_port *info = tty->driver_data;
struct cyclades_card *card;
unsigned long flags;
- void __iomem *base_addr;
- int chip, channel, index;
#ifdef CY_DEBUG_THROTTLE
char buf[64];
@@ -4191,24 +2967,9 @@ static void cy_unthrottle(struct tty_struct *tty)
if (tty->termios->c_cflag & CRTSCTS) {
card = info->card;
- channel = info->line - card->first_line;
if (!cy_is_Z(card)) {
- chip = channel >> 2;
- channel &= 0x03;
- index = card->bus_index;
- base_addr = card->base_addr +
- (cy_chip_offset[chip] << index);
-
spin_lock_irqsave(&card->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr + (CyMSVR2 << index),
- CyDTR);
- } else {
- cy_writeb(base_addr + (CyMSVR1 << index),
- CyRTS);
- }
+ cyy_change_rts_dtr(info, TIOCM_RTS, 0);
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
info->throttle = 0;
@@ -4223,8 +2984,7 @@ static void cy_stop(struct tty_struct *tty)
{
struct cyclades_card *cinfo;
struct cyclades_port *info = tty->driver_data;
- void __iomem *base_addr;
- int chip, channel, index;
+ int channel;
unsigned long flags;
#ifdef CY_DEBUG_OTHER
@@ -4237,16 +2997,9 @@ static void cy_stop(struct tty_struct *tty)
cinfo = info->card;
channel = info->line - cinfo->first_line;
if (!cy_is_Z(cinfo)) {
- index = cinfo->bus_index;
- chip = channel >> 2;
- channel &= 0x03;
- base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
-
spin_lock_irqsave(&cinfo->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char)(channel & 0x0003)); /* index channel */
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) & ~CyTxRdy);
+ cyy_writeb(info, CyCAR, channel & 0x03);
+ cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
spin_unlock_irqrestore(&cinfo->card_lock, flags);
}
} /* cy_stop */
@@ -4255,8 +3008,7 @@ static void cy_start(struct tty_struct *tty)
{
struct cyclades_card *cinfo;
struct cyclades_port *info = tty->driver_data;
- void __iomem *base_addr;
- int chip, channel, index;
+ int channel;
unsigned long flags;
#ifdef CY_DEBUG_OTHER
@@ -4268,17 +3020,10 @@ static void cy_start(struct tty_struct *tty)
cinfo = info->card;
channel = info->line - cinfo->first_line;
- index = cinfo->bus_index;
if (!cy_is_Z(cinfo)) {
- chip = channel >> 2;
- channel &= 0x03;
- base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
-
spin_lock_irqsave(&cinfo->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index),
- (u_char) (channel & 0x0003)); /* index channel */
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) | CyTxRdy);
+ cyy_writeb(info, CyCAR, channel & 0x03);
+ cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
spin_unlock_irqrestore(&cinfo->card_lock, flags);
}
} /* cy_start */
@@ -4298,17 +3043,82 @@ static void cy_hangup(struct tty_struct *tty)
return;
cy_flush_buffer(tty);
- shutdown(info);
- info->port.count = 0;
-#ifdef CY_DEBUG_COUNT
- printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n",
- current->pid);
-#endif
- info->port.tty = NULL;
- info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
- wake_up_interruptible(&info->port.open_wait);
+ cy_shutdown(info, tty);
+ tty_port_hangup(&info->port);
} /* cy_hangup */
+static int cyy_carrier_raised(struct tty_port *port)
+{
+ struct cyclades_port *info = container_of(port, struct cyclades_port,
+ port);
+ struct cyclades_card *cinfo = info->card;
+ unsigned long flags;
+ int channel = info->line - cinfo->first_line;
+ u32 cd;
+
+ spin_lock_irqsave(&cinfo->card_lock, flags);
+ cyy_writeb(info, CyCAR, channel & 0x03);
+ cd = cyy_readb(info, CyMSVR1) & CyDCD;
+ spin_unlock_irqrestore(&cinfo->card_lock, flags);
+
+ return cd;
+}
+
+static void cyy_dtr_rts(struct tty_port *port, int raise)
+{
+ struct cyclades_port *info = container_of(port, struct cyclades_port,
+ port);
+ struct cyclades_card *cinfo = info->card;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cinfo->card_lock, flags);
+ cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
+ raise ? 0 : TIOCM_RTS | TIOCM_DTR);
+ spin_unlock_irqrestore(&cinfo->card_lock, flags);
+}
+
+static int cyz_carrier_raised(struct tty_port *port)
+{
+ struct cyclades_port *info = container_of(port, struct cyclades_port,
+ port);
+
+ return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
+}
+
+static void cyz_dtr_rts(struct tty_port *port, int raise)
+{
+ struct cyclades_port *info = container_of(port, struct cyclades_port,
+ port);
+ struct cyclades_card *cinfo = info->card;
+ struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
+ int ret, channel = info->line - cinfo->first_line;
+ u32 rs;
+
+ rs = readl(&ch_ctrl->rs_control);
+ if (raise)
+ rs |= C_RS_RTS | C_RS_DTR;
+ else
+ rs &= ~(C_RS_RTS | C_RS_DTR);
+ cy_writel(&ch_ctrl->rs_control, rs);
+ ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
+ if (ret != 0)
+ printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
+ __func__, info->line, ret);
+#ifdef CY_DEBUG_DTR
+ printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
+#endif
+}
+
+static const struct tty_port_operations cyy_port_ops = {
+ .carrier_raised = cyy_carrier_raised,
+ .dtr_rts = cyy_dtr_rts,
+};
+
+static const struct tty_port_operations cyz_port_ops = {
+ .carrier_raised = cyz_carrier_raised,
+ .dtr_rts = cyz_dtr_rts,
+};
+
/*
* ---------------------------------------------------------------------
* cy_init() and friends
@@ -4320,8 +3130,7 @@ static void cy_hangup(struct tty_struct *tty)
static int __devinit cy_init_card(struct cyclades_card *cinfo)
{
struct cyclades_port *info;
- unsigned int port;
- unsigned short chip_number;
+ unsigned int channel, port;
spin_lock_init(&cinfo->card_lock);
cinfo->intr_enabled = 0;
@@ -4333,9 +3142,9 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
return -ENOMEM;
}
- for (port = cinfo->first_line; port < cinfo->first_line + cinfo->nports;
- port++) {
- info = &cinfo->ports[port - cinfo->first_line];
+ for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
+ channel++, port++) {
+ info = &cinfo->ports[channel];
tty_port_init(&info->port);
info->magic = CYCLADES_MAGIC;
info->card = cinfo;
@@ -4348,7 +3157,17 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
init_waitqueue_head(&info->delta_msr_wait);
if (cy_is_Z(cinfo)) {
+ struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
+ struct ZFW_CTRL *zfw_ctrl;
+
+ info->port.ops = &cyz_port_ops;
info->type = PORT_STARTECH;
+
+ zfw_ctrl = cinfo->base_addr +
+ (readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
+ info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
+
if (cinfo->hw_ver == ZO_V1)
info->xmit_fifo_size = CYZ_FIFO_SIZE;
else
@@ -4358,17 +3177,20 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
cyz_rx_restart, (unsigned long)info);
#endif
} else {
+ unsigned short chip_number;
int index = cinfo->bus_index;
+
+ info->port.ops = &cyy_port_ops;
info->type = PORT_CIRRUS;
info->xmit_fifo_size = CyMAX_CHAR_FIFO;
info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
info->cor2 = CyETC;
info->cor3 = 0x08; /* _very_ small rcv threshold */
- chip_number = (port - cinfo->first_line) / 4;
- info->chip_rev = readb(cinfo->base_addr +
- (cy_chip_offset[chip_number] << index) +
- (CyGFRCR << index));
+ chip_number = channel / CyPORTS_PER_CHIP;
+ info->u.cyy.base_addr = cinfo->base_addr +
+ (cy_chip_offset[chip_number] << index);
+ info->chip_rev = cyy_readb(info, CyGFRCR);
if (info->chip_rev >= CD1400_REV_J) {
/* It is a CD1400 rev. J or later */
@@ -5059,8 +3881,14 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
}
cy_card[card_no].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;
#ifdef CONFIG_CYZ_INTR
/* allocate IRQ only if board has an IRQ */
if (irq != 0 && irq != 255) {
@@ -5190,18 +4018,30 @@ static int cyclades_proc_show(struct seq_file *m, void *v)
for (j = 0; j < cy_card[i].nports; j++) {
info = &cy_card[i].ports[j];
- if (info->port.count)
+ if (info->port.count) {
+ /* XXX is the ldisc num worth this? */
+ struct tty_struct *tty;
+ struct tty_ldisc *ld;
+ int num = 0;
+ tty = tty_port_tty_get(&info->port);
+ if (tty) {
+ ld = tty_ldisc_ref(tty);
+ if (ld) {
+ num = ld->ops->num;
+ tty_ldisc_deref(ld);
+ }
+ tty_kref_put(tty);
+ }
seq_printf(m, "%3d %8lu %10lu %8lu "
- "%10lu %8lu %9lu %6ld\n", info->line,
+ "%10lu %8lu %9lu %6d\n", info->line,
(cur_jifs - info->idle_stats.in_use) /
HZ, info->idle_stats.xmit_bytes,
(cur_jifs - info->idle_stats.xmit_idle)/
HZ, info->idle_stats.recv_bytes,
(cur_jifs - info->idle_stats.recv_idle)/
HZ, info->idle_stats.overruns,
- /* FIXME: double check locking */
- (long)info->port.tty->ldisc->ops->num);
- else
+ num);
+ } else
seq_printf(m, "%3d %8lu %10lu %8lu "
"%10lu %8lu %9lu %6ld\n",
info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 24c84ae81527..60710783408b 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -20,21 +20,32 @@ static char dmi_empty_string[] = " ";
*/
static int dmi_initialized;
+static u8 *dmi_end;
+
static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s)
{
const u8 *bp = ((u8 *) dm) + dm->length;
if (s) {
s--;
- while (s > 0 && *bp) {
+ while (s > 0) {
+ /* Catch corrupt table ends before we walk into
+ undefined mappings */
+ if (bp >= dmi_end)
+ goto invalid;
+ if (*bp == 0)
+ break;
bp += strlen(bp) + 1;
s--;
}
if (*bp != 0) {
- size_t len = strlen(bp)+1;
+ /* Use strnlen in case we have a BIOS table error */
+ size_t len = strnlen(bp, dmi_end - bp) + 1;
size_t cmp_len = len > 8 ? 8 : len;
+ if (bp == dmi_end)
+ goto invalid;
if (!memcmp(bp, dmi_empty_string, cmp_len))
return dmi_empty_string;
return bp;
@@ -42,6 +53,9 @@ static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s)
}
return "";
+invalid:
+ printk(KERN_ERR "dmi: table overrun - corrupt DMI tables ?\n");
+ return dmi_empty_string;
}
static char * __init dmi_string(const struct dmi_header *dm, u8 s)
@@ -109,9 +123,11 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
if (buf == NULL)
return -1;
+ /* Remember the end mark for string walking */
+ dmi_end = buf + dmi_len;
dmi_table(buf, dmi_len, dmi_num, decode, NULL);
-
dmi_iounmap(buf, dmi_len);
+
return 0;
}
@@ -154,7 +170,7 @@ static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int inde
char *s;
int is_ff = 1, is_00 = 1, i;
- if (dmi_ident[slot])
+ if (dmi_ident[slot] || d > dmi_end - 16)
return;
for (i = 0; i < 16 && (is_ff || is_00); i++) {
@@ -182,7 +198,7 @@ static void __init dmi_save_type(const struct dmi_header *dm, int slot, int inde
const u8 *d = (u8*) dm + index;
char *s;
- if (dmi_ident[slot])
+ if (dmi_ident[slot] || d == dmi_end)
return;
s = dmi_alloc(4);
@@ -260,6 +276,11 @@ static void __init dmi_save_ipmi_device(const struct dmi_header *dm)
struct dmi_device *dev;
void * data;
+ if (((u8 *)dm) + dm->length > dmi_end) {
+ printk(KERN_ERR "dmi_save_ipmi_device: table overrun.\n");
+ return;
+ }
+
data = dmi_alloc(dm->length);
if (data == NULL) {
printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n");
@@ -285,6 +306,9 @@ static void __init dmi_save_extended_devices(const struct dmi_header *dm)
{
const u8 *d = (u8*) dm + 5;
+ if (d >= dmi_end)
+ return;
+
/* Skip disabled device */
if ((*d & 0x80) == 0)
return;
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 5c61d5fad908..527c2ce59150 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -616,6 +616,14 @@ static void sl_uninit(struct net_device *dev)
sl_free_bufs(sl);
}
+/* Hook the destructor so we can free slip devices at the right point in time */
+static void sl_free_netdev(struct net_device *dev)
+{
+ int i = dev->base_addr;
+ free_netdev(dev);
+ slip_devs[i] = NULL;
+}
+
static const struct net_device_ops sl_netdev_ops = {
.ndo_init = sl_init,
.ndo_uninit = sl_uninit,
@@ -634,7 +642,7 @@ static const struct net_device_ops sl_netdev_ops = {
static void sl_setup(struct net_device *dev)
{
dev->netdev_ops = &sl_netdev_ops;
- dev->destructor = free_netdev;
+ dev->destructor = sl_free_netdev;
dev->hard_header_len = 0;
dev->addr_len = 0;
@@ -712,8 +720,6 @@ static void sl_sync(void)
static struct slip *sl_alloc(dev_t line)
{
int i;
- int sel = -1;
- int score = -1;
struct net_device *dev = NULL;
struct slip *sl;
@@ -724,55 +730,7 @@ static struct slip *sl_alloc(dev_t line)
dev = slip_devs[i];
if (dev == NULL)
break;
-
- sl = netdev_priv(dev);
- if (sl->leased) {
- if (sl->line != line)
- continue;
- if (sl->tty)
- return NULL;
-
- /* Clear ESCAPE & ERROR flags */
- sl->flags &= (1 << SLF_INUSE);
- return sl;
- }
-
- if (sl->tty)
- continue;
-
- if (current->pid == sl->pid) {
- if (sl->line == line && score < 3) {
- sel = i;
- score = 3;
- continue;
- }
- if (score < 2) {
- sel = i;
- score = 2;
- }
- continue;
- }
- if (sl->line == line && score < 1) {
- sel = i;
- score = 1;
- continue;
- }
- if (score < 0) {
- sel = i;
- score = 0;
- }
- }
-
- if (sel >= 0) {
- i = sel;
- dev = slip_devs[i];
- if (score > 1) {
- sl = netdev_priv(dev);
- sl->flags &= (1 << SLF_INUSE);
- return sl;
- }
}
-
/* Sorry, too many, all slots in use */
if (i >= slip_maxdev)
return NULL;
@@ -909,30 +867,13 @@ err_exit:
}
/*
-
- FIXME: 1,2 are fixed 3 was never true anyway.
-
- Let me to blame a bit.
- 1. TTY module calls this funstion on soft interrupt.
- 2. TTY module calls this function WITH MASKED INTERRUPTS!
- 3. TTY module does not notify us about line discipline
- shutdown,
-
- Seems, now it is clean. The solution is to consider netdevice and
- line discipline sides as two independent threads.
-
- By-product (not desired): sl? does not feel hangups and remains open.
- It is supposed, that user level program (dip, diald, slattach...)
- will catch SIGHUP and make the rest of work.
-
- I see no way to make more with current tty code. --ANK
- */
-
-/*
* Close down a SLIP channel.
* This means flushing out any pending queues, and then returning. This
* call is serialized against other ldisc functions.
+ *
+ * We also use this method fo a hangup event
*/
+
static void slip_close(struct tty_struct *tty)
{
struct slip *sl = tty->disc_data;
@@ -951,10 +892,16 @@ static void slip_close(struct tty_struct *tty)
del_timer_sync(&sl->keepalive_timer);
del_timer_sync(&sl->outfill_timer);
#endif
-
- /* Count references from TTY module */
+ /* Flush network side */
+ unregister_netdev(sl->dev);
+ /* This will complete via sl_free_netdev */
}
+static int slip_hangup(struct tty_struct *tty)
+{
+ slip_close(tty);
+ return 0;
+}
/************************************************************************
* STANDARD SLIP ENCAPSULATION *
************************************************************************/
@@ -1311,6 +1258,7 @@ static struct tty_ldisc_ops sl_ldisc = {
.name = "slip",
.open = slip_open,
.close = slip_close,
+ .hangup = slip_hangup,
.ioctl = slip_ioctl,
.receive_buf = slip_receive_buf,
.write_wakeup = slip_write_wakeup,
@@ -1384,6 +1332,8 @@ static void __exit slip_exit(void)
}
} while (busy && time_before(jiffies, timeout));
+ /* FIXME: hangup is async so we should wait when doing this second
+ phase */
for (i = 0; i < slip_maxdev; i++) {
dev = slip_devs[i];
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index fb867a9f55e9..cf5de314e745 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -1337,14 +1337,12 @@ static void serial8250_start_tx(struct uart_port *port)
serial_out(up, UART_IER, up->ier);
if (up->bugs & UART_BUG_TXEN) {
- unsigned char lsr, iir;
+ unsigned char lsr;
lsr = serial_in(up, UART_LSR);
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
- iir = serial_in(up, UART_IIR) & 0x0f;
if ((up->port.type == PORT_RM9000) ?
- (lsr & UART_LSR_THRE &&
- (iir == UART_IIR_NO_INT || iir == UART_IIR_THRI)) :
- (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT))
+ (lsr & UART_LSR_THRE) :
+ (lsr & UART_LSR_TEMT))
transmit_chars(up);
}
}
@@ -1677,7 +1675,7 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
INIT_LIST_HEAD(&up->list);
i->head = &up->list;
spin_unlock_irq(&i->lock);
-
+ irq_flags |= up->port.irqflags;
ret = request_irq(up->port.irq, serial8250_interrupt,
irq_flags, "serial", i);
if (ret < 0)
@@ -2026,7 +2024,7 @@ static int serial8250_startup(struct uart_port *port)
* allow register changes to become visible.
*/
spin_lock_irqsave(&up->port.lock, flags);
- if (up->port.flags & UPF_SHARE_IRQ)
+ if (up->port.irqflags & IRQF_SHARED)
disable_irq_nosync(up->port.irq);
wait_for_xmitr(up, UART_LSR_THRE);
@@ -2039,7 +2037,7 @@ static int serial8250_startup(struct uart_port *port)
iir = serial_in(up, UART_IIR);
serial_out(up, UART_IER, 0);
- if (up->port.flags & UPF_SHARE_IRQ)
+ if (up->port.irqflags & IRQF_SHARED)
enable_irq(up->port.irq);
spin_unlock_irqrestore(&up->port.lock, flags);
@@ -2671,6 +2669,7 @@ static void __init serial8250_isa_init_ports(void)
i++, up++) {
up->port.iobase = old_serial_port[i].port;
up->port.irq = irq_canonicalize(old_serial_port[i].irq);
+ up->port.irqflags = old_serial_port[i].irqflags;
up->port.uartclk = old_serial_port[i].baud_base * 16;
up->port.flags = old_serial_port[i].flags;
up->port.hub6 = old_serial_port[i].hub6;
@@ -2679,7 +2678,7 @@ static void __init serial8250_isa_init_ports(void)
up->port.regshift = old_serial_port[i].iomem_reg_shift;
set_io_from_upio(&up->port);
if (share_irqs)
- up->port.flags |= UPF_SHARE_IRQ;
+ up->port.irqflags |= IRQF_SHARED;
}
}
@@ -2869,6 +2868,7 @@ int __init early_serial_setup(struct uart_port *port)
p->iobase = port->iobase;
p->membase = port->membase;
p->irq = port->irq;
+ p->irqflags = port->irqflags;
p->uartclk = port->uartclk;
p->fifosize = port->fifosize;
p->regshift = port->regshift;
@@ -2942,6 +2942,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
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;
@@ -2954,7 +2955,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
port.serial_out = p->serial_out;
port.dev = &dev->dev;
if (share_irqs)
- port.flags |= UPF_SHARE_IRQ;
+ port.irqflags |= IRQF_SHARED;
ret = serial8250_register_port(&port);
if (ret < 0) {
dev_err(&dev->dev, "unable to register port at index %d "
@@ -3096,6 +3097,7 @@ int serial8250_register_port(struct uart_port *port)
uart->port.iobase = port->iobase;
uart->port.membase = port->membase;
uart->port.irq = port->irq;
+ uart->port.irqflags = port->irqflags;
uart->port.uartclk = port->uartclk;
uart->port.fifosize = port->fifosize;
uart->port.regshift = port->regshift;
diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h
index 520260326f3d..9b34b04f64f9 100644
--- a/drivers/serial/8250.h
+++ b/drivers/serial/8250.h
@@ -20,6 +20,7 @@ struct old_serial_port {
unsigned int baud_base;
unsigned int port;
unsigned int irq;
+ unsigned long irqflags;
unsigned int flags;
unsigned char hub6;
unsigned char io_type;
diff --git a/include/linux/cyclades.h b/include/linux/cyclades.h
index 1fbdea4f08eb..bbebef7713b3 100644
--- a/include/linux/cyclades.h
+++ b/include/linux/cyclades.h
@@ -499,6 +499,7 @@ struct cyclades_card {
void __iomem *p9050;
struct RUNTIME_9060 __iomem *p9060;
} ctl_addr;
+ struct BOARD_CTRL __iomem *board_ctrl; /* cyz specific */
int irq;
unsigned int num_chips; /* 0 if card absent, -1 if Z/PCI, else Y */
unsigned int first_line; /* minor number of first channel on card */
@@ -541,6 +542,15 @@ struct cyclades_port {
int magic;
struct tty_port port;
struct cyclades_card *card;
+ union {
+ struct {
+ void __iomem *base_addr;
+ } cyy;
+ struct {
+ struct CH_CTRL __iomem *ch_ctrl;
+ struct BUF_CTRL __iomem *buf_ctrl;
+ } cyz;
+ } u;
int line;
int flags; /* defined in tty.h */
int type; /* UART type */
diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h
index 29f62e1733ff..ad6bdf5a5970 100644
--- a/include/linux/kfifo.h
+++ b/include/linux/kfifo.h
@@ -38,7 +38,7 @@ extern struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask,
spinlock_t *lock);
extern void kfifo_free(struct kfifo *fifo);
extern unsigned int __kfifo_put(struct kfifo *fifo,
- unsigned char *buffer, unsigned int len);
+ const unsigned char *buffer, unsigned int len);
extern unsigned int __kfifo_get(struct kfifo *fifo,
unsigned char *buffer, unsigned int len);
@@ -77,7 +77,7 @@ static inline void kfifo_reset(struct kfifo *fifo)
* bytes copied.
*/
static inline unsigned int kfifo_put(struct kfifo *fifo,
- unsigned char *buffer, unsigned int len)
+ const unsigned char *buffer, unsigned int len)
{
unsigned long flags;
unsigned int ret;
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index d4d2a78ad43e..fb46aba11fb5 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -22,6 +22,7 @@ struct plat_serial8250_port {
void __iomem *membase; /* ioremap cookie or NULL */
resource_size_t mapbase; /* resource base */
unsigned int irq; /* interrupt number */
+ unsigned long irqflags; /* request_irq flags */
unsigned int uartclk; /* UART clock rate */
void *private_data;
unsigned char regshift; /* register shift */
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 23d2fb051f97..3cd255f0b211 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -265,6 +265,7 @@ struct uart_port {
unsigned int (*serial_in)(struct uart_port *, int);
void (*serial_out)(struct uart_port *, int, int);
unsigned int irq; /* irq number */
+ unsigned long irqflags; /* irq flags */
unsigned int uartclk; /* base uart clock */
unsigned int fifosize; /* tx fifo size */
unsigned char x_char; /* xon/xoff char */
diff --git a/kernel/kfifo.c b/kernel/kfifo.c
index 26539e3228e5..3765ff3c1bbe 100644
--- a/kernel/kfifo.c
+++ b/kernel/kfifo.c
@@ -117,7 +117,7 @@ EXPORT_SYMBOL(kfifo_free);
* writer, you don't need extra locking to use these functions.
*/
unsigned int __kfifo_put(struct kfifo *fifo,
- unsigned char *buffer, unsigned int len)
+ const unsigned char *buffer, unsigned int len)
{
unsigned int l;