diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2009-07-20 13:19:49 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2009-07-20 13:19:49 +1000 |
commit | b1462214d83d57adceaf690df91ac08763e3e681 (patch) | |
tree | e1ded6c84e653903051e4cdb6ab6bfa1d675ffbb | |
parent | 1c0c96fa6511d49c6c08c52ce36f871ab7a13c98 (diff) | |
parent | 4a826030412baf29b4833d2c4334461bc0927aaf (diff) |
Merge commit 'refs/next/20090713/ttydev'
Conflicts:
drivers/usb/serial/generic.c
drivers/usb/serial/pl2303.c
-rw-r--r-- | arch/arm/mach-omap1/board-ams-delta.c | 38 | ||||
-rw-r--r-- | drivers/char/cyclades.c | 2276 | ||||
-rw-r--r-- | drivers/char/vt.c | 4 | ||||
-rw-r--r-- | drivers/char/vt_ioctl.c | 279 | ||||
-rw-r--r-- | drivers/firmware/dmi_scan.c | 34 | ||||
-rw-r--r-- | drivers/net/slip.c | 96 | ||||
-rw-r--r-- | drivers/serial/8250.c | 18 | ||||
-rw-r--r-- | drivers/serial/8250.h | 1 | ||||
-rw-r--r-- | drivers/usb/serial/mos7720.c | 120 | ||||
-rw-r--r-- | drivers/usb/serial/mos7840.c | 115 | ||||
-rw-r--r-- | include/linux/cyclades.h | 10 | ||||
-rw-r--r-- | include/linux/ioport.h | 4 | ||||
-rw-r--r-- | include/linux/kfifo.h | 4 | ||||
-rw-r--r-- | include/linux/serial_8250.h | 1 | ||||
-rw-r--r-- | include/linux/serial_core.h | 1 | ||||
-rw-r--r-- | include/linux/vt.h | 32 | ||||
-rw-r--r-- | include/linux/vt_kern.h | 16 | ||||
-rw-r--r-- | kernel/kfifo.c | 2 | ||||
-rw-r--r-- | kernel/power/console.c | 63 | ||||
-rw-r--r-- | kernel/resource.c | 15 |
20 files changed, 1044 insertions, 2085 deletions
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c index 8b40aace9db4..10c2265b05d4 100644 --- a/arch/arm/mach-omap1/board-ams-delta.c +++ b/arch/arm/mach-omap1/board-ams-delta.c @@ -15,8 +15,11 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/input.h> +#include <linux/interrupt.h> #include <linux/platform_device.h> +#include <linux/serial_8250.h> +#include <asm/serial.h> #include <mach/hardware.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> @@ -235,6 +238,41 @@ static void __init ams_delta_init(void) platform_add_devices(ams_delta_devices, ARRAY_SIZE(ams_delta_devices)); } +static struct plat_serial8250_port ams_delta_modem_ports[] = { + { + .membase = (void *) AMS_DELTA_MODEM_VIRT, + .mapbase = AMS_DELTA_MODEM_PHYS, + .irq = -EINVAL, /* changed later */ + .flags = UPF_BOOT_AUTOCONF, + .irqflags = IRQF_TRIGGER_RISING, + .iotype = UPIO_MEM, + .regshift = 1, + .uartclk = BASE_BAUD * 16, + }, + { }, +}; + +static struct platform_device ams_delta_modem_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM1, + .dev = { + .platform_data = ams_delta_modem_ports, + }, +}; + +static int __init ams_delta_modem_init(void) +{ + omap_cfg_reg(M14_1510_GPIO2); + ams_delta_modem_ports[0].irq = gpio_to_irq(2); + + ams_delta_latch2_write( + AMS_DELTA_LATCH2_MODEM_NRESET | AMS_DELTA_LATCH2_MODEM_CODEC, + AMS_DELTA_LATCH2_MODEM_NRESET | AMS_DELTA_LATCH2_MODEM_CODEC); + + return platform_device_register(&ams_delta_modem_device); +} +arch_initcall(ams_delta_modem_init); + static void __init ams_delta_map_io(void) { omap1_map_common_io(); diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 2dafc2da0648..f518e0b5b47d 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 @@ -648,9 +80,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> @@ -660,13 +90,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) @@ -756,25 +184,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, @@ -782,13 +210,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 @@ -805,7 +233,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 @@ -814,7 +242,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, @@ -827,7 +255,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 */ @@ -850,7 +278,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 *); @@ -869,6 +297,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; @@ -893,7 +335,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) { @@ -909,7 +351,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 ********/ @@ -921,13 +363,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); } @@ -937,10 +380,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 */ @@ -960,12 +409,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), @@ -973,7 +422,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); @@ -999,7 +448,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); @@ -1008,26 +457,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) @@ -1041,28 +489,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) { @@ -1074,8 +523,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 */ @@ -1099,7 +548,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; @@ -1110,7 +559,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++; @@ -1121,16 +570,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; @@ -1154,9 +605,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; } @@ -1165,7 +616,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; @@ -1173,14 +624,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; } @@ -1188,27 +639,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, @@ -1225,15 +672,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--; } @@ -1241,17 +688,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; @@ -1259,13 +708,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) { @@ -1283,31 +733,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); } } } @@ -1315,10 +762,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 @@ -1389,6 +837,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 *******/ @@ -1398,15 +896,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); @@ -1422,19 +914,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) { @@ -1449,11 +935,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 @@ -1542,11 +1027,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 @@ -1621,34 +1105,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, ¶m) == 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); @@ -1669,15 +1143,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: @@ -1706,7 +1177,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: @@ -1716,7 +1187,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: @@ -1729,6 +1200,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); } } @@ -1774,10 +1246,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; @@ -1789,10 +1257,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; @@ -1802,13 +1266,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; @@ -1824,13 +1292,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; @@ -1842,15 +1309,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; } @@ -1861,96 +1324,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 */ @@ -1969,32 +1389,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"); @@ -2003,28 +1413,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 @@ -2047,12 +1449,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; @@ -2060,17 +1461,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. */ @@ -2082,47 +1472,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) { @@ -2132,23 +1500,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); @@ -2165,199 +1520,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. @@ -2436,7 +1598,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; @@ -2462,11 +1623,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 " @@ -2476,6 +1637,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"); @@ -2490,8 +1652,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; @@ -2535,13 +1695,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 @@ -2603,75 +1758,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 */ @@ -2683,15 +1786,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 " @@ -2705,30 +1803,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 @@ -2871,18 +1951,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", @@ -2891,20 +1966,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); @@ -2957,48 +2023,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) @@ -3107,124 +2169,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) @@ -3335,45 +2341,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 || @@ -3403,10 +2402,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 */ @@ -3422,24 +2421,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 { @@ -3453,34 +2442,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) { @@ -3495,27 +2473,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 */ @@ -3526,150 +2499,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 @@ -3734,41 +2610,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; @@ -3777,55 +2630,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; @@ -3834,36 +2655,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- @@ -3875,8 +2695,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; @@ -3892,7 +2711,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); @@ -3901,10 +2724,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); @@ -3913,21 +2737,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; @@ -3938,7 +2761,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; @@ -3946,16 +2768,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); @@ -3971,17 +2792,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; /* @@ -3990,46 +2802,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; } @@ -4055,7 +2850,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)) { @@ -4112,8 +2907,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]; @@ -4135,24 +2928,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; @@ -4170,8 +2948,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]; @@ -4192,24 +2968,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; @@ -4224,8 +2985,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 @@ -4238,16 +2998,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 */ @@ -4256,8 +3009,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 @@ -4269,17 +3021,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 */ @@ -4299,17 +3044,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 @@ -4321,8 +3131,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; @@ -4334,9 +3143,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; @@ -4349,7 +3158,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 @@ -4359,17 +3178,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 */ @@ -5060,8 +3882,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) { @@ -5191,18 +4019,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/char/vt.c b/drivers/char/vt.c index 404f4c1ee431..9a01270f8f57 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -252,7 +252,6 @@ static void notify_update(struct vc_data *vc) struct vt_notifier_param param = { .vc = vc }; atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, ¶m); } - /* * Low-Level Functions */ @@ -935,6 +934,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, if (CON_IS_VISIBLE(vc)) update_screen(vc); + vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num); return err; } @@ -3641,6 +3641,7 @@ void do_blank_screen(int entering_gfx) blank_state = blank_vesa_wait; mod_timer(&console_timer, jiffies + vesa_off_interval); } + vt_event_post(VT_EVENT_BLANK, vc->vc_num, vc->vc_num); } EXPORT_SYMBOL(do_blank_screen); @@ -3685,6 +3686,7 @@ void do_unblank_screen(int leaving_gfx) console_blank_hook(0); set_palette(vc); set_cursor(vc); + vt_event_post(VT_EVENT_UNBLANK, vc->vc_num, vc->vc_num); } EXPORT_SYMBOL(do_unblank_screen); diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 95189f288f8c..0fceb8f4d6f2 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -16,6 +16,7 @@ #include <linux/tty.h> #include <linux/timer.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/kd.h> #include <linux/vt.h> #include <linux/string.h> @@ -62,6 +63,133 @@ extern struct tty_driver *console_driver; static void complete_change_console(struct vc_data *vc); /* + * User space VT_EVENT handlers + */ + +struct vt_event_wait { + struct list_head list; + struct vt_event event; + int done; +}; + +static LIST_HEAD(vt_events); +static DEFINE_SPINLOCK(vt_event_lock); +static DECLARE_WAIT_QUEUE_HEAD(vt_event_waitqueue); + +/** + * vt_event_post + * @event: the event that occurred + * @old: old console + * @new: new console + * + * Post an VT event to interested VT handlers + */ + +void vt_event_post(unsigned int event, unsigned int old, unsigned int new) +{ + struct list_head *pos, *head; + unsigned long flags; + int wake = 0; + + spin_lock_irqsave(&vt_event_lock, flags); + head = &vt_events; + + list_for_each(pos, head) { + struct vt_event_wait *ve = list_entry(pos, + struct vt_event_wait, list); + if (!(ve->event.event & event)) + continue; + ve->event.event = event; + /* kernel view is consoles 0..n-1, user space view is + console 1..n with 0 meaning current, so we must bias */ + ve->event.old = old + 1; + ve->event.new = new + 1; + wake = 1; + ve->done = 1; + } + spin_unlock_irqrestore(&vt_event_lock, flags); + if (wake) + wake_up_interruptible(&vt_event_waitqueue); +} + +/** + * vt_event_wait - wait for an event + * @vw: our event + * + * Waits for an event to occur which completes our vt_event_wait + * structure. On return the structure has wv->done set to 1 for success + * or 0 if some event such as a signal ended the wait. + */ + +static void vt_event_wait(struct vt_event_wait *vw) +{ + unsigned long flags; + /* Prepare the event */ + INIT_LIST_HEAD(&vw->list); + vw->done = 0; + /* Queue our event */ + spin_lock_irqsave(&vt_event_lock, flags); + list_add(&vw->list, &vt_events); + spin_unlock_irqrestore(&vt_event_lock, flags); + /* Wait for it to pass */ + wait_event_interruptible(vt_event_waitqueue, vw->done); + /* Dequeue it */ + spin_lock_irqsave(&vt_event_lock, flags); + list_del(&vw->list); + spin_unlock_irqrestore(&vt_event_lock, flags); +} + +/** + * vt_event_wait_ioctl - event ioctl handler + * @arg: argument to ioctl + * + * Implement the VT_WAITEVENT ioctl using the VT event interface + */ + +static int vt_event_wait_ioctl(struct vt_event __user *event) +{ + struct vt_event_wait vw; + + if (copy_from_user(&vw.event, event, sizeof(struct vt_event))) + return -EFAULT; + /* Highest supported event for now */ + if (vw.event.event & ~VT_MAX_EVENT) + return -EINVAL; + + vt_event_wait(&vw); + /* If it occurred report it */ + if (vw.done) { + if (copy_to_user(event, &vw.event, sizeof(struct vt_event))) + return -EFAULT; + return 0; + } + return -EINTR; +} + +/** + * vt_waitactive - active console wait + * @event: event code + * @n: new console + * + * Helper for event waits. Used to implement the legacy + * event waiting ioctls in terms of events + */ + +int vt_waitactive(int n) +{ + struct vt_event_wait vw; + do { + if (n == fg_console + 1) + break; + vw.event.event = VT_EVENT_SWITCH; + vt_event_wait(&vw); + if (vw.done == 0) + return -EINTR; + } while (vw.event.new != n); + return 0; +} + +/* * these are the valid i/o ports we're allowed to change. they map all the * video ports */ @@ -360,6 +488,8 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_ return 0; } + + /* * We handle the console-specific ioctl's here. We allow the * capability to modify any console, not just the fg_console. @@ -842,6 +972,41 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, } break; + case VT_SETACTIVATE: + { + struct vt_setactivate vsa; + + if (!perm) + goto eperm; + + if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg, + sizeof(struct vt_setactivate))) + return -EFAULT; + if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES) + ret = -ENXIO; + else { + vsa.console--; + acquire_console_sem(); + ret = vc_allocate(vsa.console); + if (ret == 0) { + struct vc_data *nvc; + /* This is safe providing we don't drop the + console sem between vc_allocate and + finishing referencing nvc */ + nvc = vc_cons[vsa.console].d; + nvc->vt_mode = vsa.mode; + nvc->vt_mode.frsig = 0; + put_pid(nvc->vt_pid); + nvc->vt_pid = get_pid(task_pid(current)); + } + release_console_sem(); + if (ret) + break; + /* Commence switch and lock */ + set_console(arg); + } + } + /* * wait until the specified VT has been activated */ @@ -851,7 +1016,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, if (arg == 0 || arg > MAX_NR_CONSOLES) ret = -ENXIO; else - ret = vt_waitactive(arg - 1); + ret = vt_waitactive(arg); break; /* @@ -1159,6 +1324,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ret = put_user(vc->vc_hi_font_mask, (unsigned short __user *)arg); break; + case VT_WAITEVENT: + ret = vt_event_wait_ioctl((struct vt_event __user *)arg); + break; default: ret = -ENOIOCTLCMD; } @@ -1170,54 +1338,6 @@ eperm: goto out; } -/* - * Sometimes we want to wait until a particular VT has been activated. We - * do it in a very simple manner. Everybody waits on a single queue and - * get woken up at once. Those that are satisfied go on with their business, - * while those not ready go back to sleep. Seems overkill to add a wait - * to each vt just for this - usually this does nothing! - */ -static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue); - -/* - * Sleeps until a vt is activated, or the task is interrupted. Returns - * 0 if activation, -EINTR if interrupted by a signal handler. - */ -int vt_waitactive(int vt) -{ - int retval; - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&vt_activate_queue, &wait); - for (;;) { - retval = 0; - - /* - * Synchronize with redraw_screen(). By acquiring the console - * semaphore we make sure that the console switch is completed - * before we return. If we didn't wait for the semaphore, we - * could return at a point where fg_console has already been - * updated, but the console switch hasn't been completed. - */ - acquire_console_sem(); - set_current_state(TASK_INTERRUPTIBLE); - if (vt == fg_console) { - release_console_sem(); - break; - } - release_console_sem(); - retval = -ERESTARTNOHAND; - if (signal_pending(current)) - break; - schedule(); - } - remove_wait_queue(&vt_activate_queue, &wait); - __set_current_state(TASK_RUNNING); - return retval; -} - -#define vt_wake_waitactive() wake_up(&vt_activate_queue) - void reset_vc(struct vc_data *vc) { vc->vc_mode = KD_TEXT; @@ -1257,11 +1377,13 @@ void vc_SAK(struct work_struct *work) } /* - * Performs the back end of a vt switch + * Performs the back end of a vt switch. Called under the console + * semaphore. */ static void complete_change_console(struct vc_data *vc) { unsigned char old_vc_mode; + int old = fg_console; last_console = fg_console; @@ -1325,7 +1447,7 @@ static void complete_change_console(struct vc_data *vc) /* * Wake anyone waiting for their VT to activate */ - vt_wake_waitactive(); + vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num); return; } @@ -1398,3 +1520,58 @@ void change_console(struct vc_data *new_vc) complete_change_console(new_vc); } + +/* Perform a kernel triggered VT switch for suspend/resume */ + +static int disable_vt_switch; + +int vt_move_to_console(unsigned int vt, int alloc) +{ + int prev; + + acquire_console_sem(); + /* Graphics mode - up to X */ + if (disable_vt_switch) { + release_console_sem(); + return 0; + } + prev = fg_console; + + if (alloc && vc_allocate(vt)) { + /* we can't have a free VC for now. Too bad, + * we don't want to mess the screen for now. */ + release_console_sem(); + return -ENOSPC; + } + + if (set_console(vt)) { + /* + * We're unable to switch to the SUSPEND_CONSOLE. + * Let the calling function know so it can decide + * what to do. + */ + release_console_sem(); + return -EIO; + } + release_console_sem(); + if (vt_waitactive(vt)) { + pr_debug("Suspend: Can't switch VCs."); + return -EINTR; + } + return prev; +} + +/* + * Normally during a suspend, we allocate a new console and switch to it. + * When we resume, we switch back to the original console. This switch + * can be slow, so on systems where the framebuffer can handle restoration + * of video registers anyways, there's little point in doing the console + * switch. This function allows you to disable it by passing it '0'. + */ +void pm_set_vt_switch(int do_switch) +{ + acquire_console_sem(); + disable_vt_switch = !do_switch; + release_console_sem(); +} +EXPORT_SYMBOL(pm_set_vt_switch); 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 899c4a2112c9..32eeb4b9245d 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..1fd4894d9b51 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1677,7 +1677,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 +2026,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 +2039,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); @@ -2272,7 +2272,9 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios, /* * Ask the core to calculate the divisor for us. */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + baud = uart_get_baud_rate(port, termios, old, + port->uartclk / 16 / 0xffff, + port->uartclk / 16); quot = serial8250_get_divisor(port, baud); /* @@ -2671,6 +2673,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 +2682,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 +2872,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 +2946,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 +2959,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 +3101,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/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index bfc5ce000ef9..47df63809e98 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -85,7 +85,7 @@ static int debug; #define MOSCHIP_DEVICE_ID_7720 0x7720 #define MOSCHIP_DEVICE_ID_7715 0x7715 -static struct usb_device_id moschip_port_id_table [] = { +static struct usb_device_id moschip_port_id_table[] = { { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) }, { } /* terminating entry */ }; @@ -378,10 +378,14 @@ static int mos7720_open(struct tty_struct *tty, /* Initialize MCS7720 -- Write Init values to corresponding Registers * * Register Index + * 0 : THR/RHR * 1 : IER * 2 : FCR * 3 : LCR * 4 : MCR + * 5 : LSR + * 6 : MSR + * 7 : SPR * * 0x08 : SP1/2 Control Reg */ @@ -1250,20 +1254,88 @@ static void mos7720_set_termios(struct tty_struct *tty, static int get_lsr_info(struct tty_struct *tty, struct moschip_port *mos7720_port, unsigned int __user *value) { - int count; + struct usb_serial_port *port = tty->driver_data; unsigned int result = 0; + unsigned char data = 0; + int port_number = port->number - port->serial->minor; + int count; count = mos7720_chars_in_buffer(tty); if (count == 0) { - dbg("%s -- Empty", __func__); - result = TIOCSER_TEMT; + send_mos_cmd(port->serial, MOS_READ, port_number, + UART_LSR, &data); + if ((data & (UART_LSR_TEMT | UART_LSR_THRE)) + == (UART_LSR_TEMT | UART_LSR_THRE)) { + dbg("%s -- Empty", __func__); + result = TIOCSER_TEMT; + } } - if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; return 0; } +static int mos7720_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct usb_serial_port *port = tty->driver_data; + struct moschip_port *mos7720_port = usb_get_serial_port_data(port); + unsigned int result = 0; + unsigned int mcr ; + unsigned int msr ; + + dbg("%s - port %d", __func__, port->number); + + mcr = mos7720_port->shadowMCR; + msr = mos7720_port->shadowMSR; + + result = ((mcr & UART_MCR_DTR) ? TIOCM_DTR : 0) /* 0x002 */ + | ((mcr & UART_MCR_RTS) ? TIOCM_RTS : 0) /* 0x004 */ + | ((msr & UART_MSR_CTS) ? TIOCM_CTS : 0) /* 0x020 */ + | ((msr & UART_MSR_DCD) ? TIOCM_CAR : 0) /* 0x040 */ + | ((msr & UART_MSR_RI) ? TIOCM_RI : 0) /* 0x080 */ + | ((msr & UART_MSR_DSR) ? TIOCM_DSR : 0); /* 0x100 */ + + dbg("%s -- %x", __func__, result); + + return result; +} + +static int mos7720_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + struct usb_serial_port *port = tty->driver_data; + struct moschip_port *mos7720_port = usb_get_serial_port_data(port); + unsigned int mcr ; + unsigned char lmcr; + + dbg("%s - port %d", __func__, port->number); + dbg("he was at tiocmget"); + + mcr = mos7720_port->shadowMCR; + + if (set & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (set & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (set & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + if (clear & TIOCM_RTS) + mcr &= ~UART_MCR_RTS; + if (clear & TIOCM_DTR) + mcr &= ~UART_MCR_DTR; + if (clear & TIOCM_LOOP) + mcr &= ~UART_MCR_LOOP; + + mos7720_port->shadowMCR = mcr; + lmcr = mos7720_port->shadowMCR; + + send_mos_cmd(port->serial, MOS_WRITE, + port->number - port->serial->minor, UART_MCR, &lmcr); + + return 0; +} + static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, unsigned int __user *value) { @@ -1301,14 +1373,6 @@ static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, mcr &= ~UART_MCR_LOOP; break; - case TIOCMSET: - /* turn off the RTS and DTR and LOOPBACK - * and then only turn on what was asked to */ - mcr &= ~(UART_MCR_RTS | UART_MCR_DTR | UART_MCR_LOOP); - mcr |= ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0); - mcr |= ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0); - mcr |= ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0); - break; } mos7720_port->shadowMCR = mcr; @@ -1320,28 +1384,6 @@ static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, return 0; } -static int get_modem_info(struct moschip_port *mos7720_port, - unsigned int __user *value) -{ - unsigned int result = 0; - unsigned int msr = mos7720_port->shadowMSR; - unsigned int mcr = mos7720_port->shadowMCR; - - result = ((mcr & UART_MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ - | ((mcr & UART_MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */ - | ((msr & UART_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ - | ((msr & UART_MSR_DCD) ? TIOCM_CAR: 0) /* 0x040 */ - | ((msr & UART_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ - | ((msr & UART_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ - - - dbg("%s -- %x", __func__, result); - - if (copy_to_user(value, &result, sizeof(int))) - return -EFAULT; - return 0; -} - static int get_serial_info(struct moschip_port *mos7720_port, struct serial_struct __user *retinfo) { @@ -1392,17 +1434,11 @@ static int mos7720_ioctl(struct tty_struct *tty, struct file *file, /* FIXME: These should be using the mode methods */ case TIOCMBIS: case TIOCMBIC: - case TIOCMSET: dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __func__, port->number); return set_modem_info(mos7720_port, cmd, (unsigned int __user *)arg); - case TIOCMGET: - dbg("%s (%d) TIOCMGET", __func__, port->number); - return get_modem_info(mos7720_port, - (unsigned int __user *)arg); - case TIOCGSERIAL: dbg("%s (%d) TIOCGSERIAL", __func__, port->number); return get_serial_info(mos7720_port, @@ -1557,6 +1593,8 @@ static struct usb_serial_driver moschip7720_2port_driver = { .attach = mos7720_startup, .release = mos7720_release, .ioctl = mos7720_ioctl, + .tiocmget = mos7720_tiocmget, + .tiocmset = mos7720_tiocmset, .set_termios = mos7720_set_termios, .write = mos7720_write, .write_room = mos7720_write_room, diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index c31940a307f8..29fa159195f3 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2129,106 +2129,6 @@ static int mos7840_get_lsr_info(struct tty_struct *tty, } /***************************************************************************** - * mos7840_set_modem_info - * function to set modem info - *****************************************************************************/ - -/* FIXME: Should be using the model control hooks */ - -static int mos7840_set_modem_info(struct moschip_port *mos7840_port, - unsigned int cmd, unsigned int __user *value) -{ - unsigned int mcr; - unsigned int arg; - __u16 Data; - int status; - struct usb_serial_port *port; - - if (mos7840_port == NULL) - return -1; - - port = (struct usb_serial_port *)mos7840_port->port; - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); - return -1; - } - - mcr = mos7840_port->shadowMCR; - - if (copy_from_user(&arg, value, sizeof(int))) - return -EFAULT; - - switch (cmd) { - case TIOCMBIS: - if (arg & TIOCM_RTS) - mcr |= MCR_RTS; - if (arg & TIOCM_DTR) - mcr |= MCR_RTS; - if (arg & TIOCM_LOOP) - mcr |= MCR_LOOPBACK; - break; - - case TIOCMBIC: - if (arg & TIOCM_RTS) - mcr &= ~MCR_RTS; - if (arg & TIOCM_DTR) - mcr &= ~MCR_RTS; - if (arg & TIOCM_LOOP) - mcr &= ~MCR_LOOPBACK; - break; - - case TIOCMSET: - /* turn off the RTS and DTR and LOOPBACK - * and then only turn on what was asked to */ - mcr &= ~(MCR_RTS | MCR_DTR | MCR_LOOPBACK); - mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0); - mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0); - mcr |= ((arg & TIOCM_LOOP) ? MCR_LOOPBACK : 0); - break; - } - - lock_kernel(); - mos7840_port->shadowMCR = mcr; - - Data = mos7840_port->shadowMCR; - status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); - unlock_kernel(); - if (status < 0) { - dbg("setting MODEM_CONTROL_REGISTER Failed"); - return -1; - } - - return 0; -} - -/***************************************************************************** - * mos7840_get_modem_info - * function to get modem info - *****************************************************************************/ - -static int mos7840_get_modem_info(struct moschip_port *mos7840_port, - unsigned int __user *value) -{ - unsigned int result = 0; - __u16 msr; - unsigned int mcr = mos7840_port->shadowMCR; - mos7840_get_uart_reg(mos7840_port->port, - MODEM_STATUS_REGISTER, &msr); - result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) /* 0x002 */ - |((mcr & MCR_RTS) ? TIOCM_RTS : 0) /* 0x004 */ - |((msr & MOS7840_MSR_CTS) ? TIOCM_CTS : 0) /* 0x020 */ - |((msr & MOS7840_MSR_CD) ? TIOCM_CAR : 0) /* 0x040 */ - |((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0) /* 0x080 */ - |((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0); /* 0x100 */ - - dbg("%s -- %x", __func__, result); - - if (copy_to_user(value, &result, sizeof(int))) - return -EFAULT; - return 0; -} - -/***************************************************************************** * mos7840_get_serial_info * function to get information about serial port *****************************************************************************/ @@ -2276,7 +2176,6 @@ static int mos7840_ioctl(struct tty_struct *tty, struct file *file, struct async_icount cnow; struct async_icount cprev; struct serial_icounter_struct icount; - int mosret = 0; if (mos7840_port_paranoia_check(port, __func__)) { dbg("%s", "Invalid port"); @@ -2298,20 +2197,6 @@ static int mos7840_ioctl(struct tty_struct *tty, struct file *file, return mos7840_get_lsr_info(tty, argp); return 0; - /* FIXME: use the modem hooks and remove this */ - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __func__, - port->number); - mosret = - mos7840_set_modem_info(mos7840_port, cmd, argp); - return mosret; - - case TIOCMGET: - dbg("%s (%d) TIOCMGET", __func__, port->number); - return mos7840_get_modem_info(mos7840_port, argp); - case TIOCGSERIAL: dbg("%s (%d) TIOCGSERIAL", __func__, port->number); return mos7840_get_serial_info(mos7840_port, argp); 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/ioport.h b/include/linux/ioport.h index 786e7b8cece9..c9a3a41036e3 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -50,6 +50,7 @@ struct resource_list { #define IORESOURCE_STARTALIGN 0x00040000 /* start field is alignment */ #define IORESOURCE_MEM_64 0x00100000 +#define IORESOURCE_MUXED 0x00200000 /* Resource is software muxed */ #define IORESOURCE_EXCLUSIVE 0x08000000 /* Userland may not map this resource */ #define IORESOURCE_DISABLED 0x10000000 @@ -136,7 +137,8 @@ static inline unsigned long resource_type(struct resource *res) } /* Convenience shorthand with allocation */ -#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), 0) +#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), 0) +#define request_muxed_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), IORESOURCE_MUXED) #define __request_mem_region(start,n,name, excl) __request_region(&iomem_resource, (start), (n), (name), excl) #define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0) #define request_mem_region_exclusive(start,n,name) \ 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/include/linux/vt.h b/include/linux/vt.h index 02c1c0288770..7afca0d72139 100644 --- a/include/linux/vt.h +++ b/include/linux/vt.h @@ -1,17 +1,6 @@ #ifndef _LINUX_VT_H #define _LINUX_VT_H -#ifdef __KERNEL__ -struct notifier_block; - -struct vt_notifier_param { - struct vc_data *vc; /* VC on which the update happened */ - unsigned int c; /* Printed char */ -}; - -extern int register_vt_notifier(struct notifier_block *nb); -extern int unregister_vt_notifier(struct notifier_block *nb); -#endif /* * These constants are also useful for user-level apps (e.g., VC @@ -74,4 +63,25 @@ struct vt_consize { #define VT_UNLOCKSWITCH 0x560C /* allow vt switching */ #define VT_GETHIFONTMASK 0x560D /* return hi font mask */ +struct vt_event { + unsigned int event; +#define VT_EVENT_SWITCH 0x0001 /* Console switch */ +#define VT_EVENT_BLANK 0x0002 /* Screen blank */ +#define VT_EVENT_UNBLANK 0x0004 /* Screen unblank */ +#define VT_EVENT_RESIZE 0x0008 /* Resize display */ +#define VT_MAX_EVENT 0x000F + unsigned int old; /* Old console */ + unsigned int new; /* New console (if changing) */ + unsigned int pad[4]; /* Padding for expansion */ +}; + +#define VT_WAITEVENT 0x560E /* Wait for an event */ + +struct vt_setactivate { + unsigned int console; + struct vt_mode mode; +}; + +#define VT_SETACTIVATE 0x560F /* Activate and set the mode of a console */ + #endif /* _LINUX_VT_H */ diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 2f1113467f70..c0c4e1103a73 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -13,6 +13,7 @@ #include <linux/console_struct.h> #include <linux/mm.h> #include <linux/consolemap.h> +#include <linux/notifier.h> /* * Presently, a lot of graphics programs do not restore the contents of @@ -91,7 +92,8 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc); #endif /* vt.c */ -int vt_waitactive(int vt); +void vt_event_post(unsigned int event, unsigned int old, unsigned int new); +int vt_waitactive(int n); void change_console(struct vc_data *new_vc); void reset_vc(struct vc_data *vc); extern int unbind_con_driver(const struct consw *csw, int first, int last, @@ -116,4 +118,16 @@ struct vt_spawn_console { }; extern struct vt_spawn_console vt_spawn_con; +extern int vt_move_to_console(unsigned int vt, int alloc); + +/* Interfaces for VC notification of character events (for accessibility etc) */ + +struct vt_notifier_param { + struct vc_data *vc; /* VC on which the update happened */ + unsigned int c; /* Printed char */ +}; + +extern int register_vt_notifier(struct notifier_block *nb); +extern int unregister_vt_notifier(struct notifier_block *nb); + #endif /* _VT_KERN_H */ 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; diff --git a/kernel/power/console.c b/kernel/power/console.c index a3961b205de7..5187136fe1de 100644 --- a/kernel/power/console.c +++ b/kernel/power/console.c @@ -14,56 +14,13 @@ #define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1) static int orig_fgconsole, orig_kmsg; -static int disable_vt_switch; - -/* - * Normally during a suspend, we allocate a new console and switch to it. - * When we resume, we switch back to the original console. This switch - * can be slow, so on systems where the framebuffer can handle restoration - * of video registers anyways, there's little point in doing the console - * switch. This function allows you to disable it by passing it '0'. - */ -void pm_set_vt_switch(int do_switch) -{ - acquire_console_sem(); - disable_vt_switch = !do_switch; - release_console_sem(); -} -EXPORT_SYMBOL(pm_set_vt_switch); int pm_prepare_console(void) { - acquire_console_sem(); - - if (disable_vt_switch) { - release_console_sem(); - return 0; - } - - orig_fgconsole = fg_console; - - if (vc_allocate(SUSPEND_CONSOLE)) { - /* we can't have a free VC for now. Too bad, - * we don't want to mess the screen for now. */ - release_console_sem(); + orig_fgconsole = vt_move_to_console(SUSPEND_CONSOLE, 1); + if (orig_fgconsole < 0) return 1; - } - if (set_console(SUSPEND_CONSOLE)) { - /* - * We're unable to switch to the SUSPEND_CONSOLE. - * Let the calling function know so it can decide - * what to do. - */ - release_console_sem(); - return 1; - } - release_console_sem(); - - if (vt_waitactive(SUSPEND_CONSOLE)) { - pr_debug("Suspend: Can't switch VCs."); - return 1; - } orig_kmsg = kmsg_redirect; kmsg_redirect = SUSPEND_CONSOLE; return 0; @@ -71,19 +28,9 @@ int pm_prepare_console(void) void pm_restore_console(void) { - acquire_console_sem(); - if (disable_vt_switch) { - release_console_sem(); - return; - } - set_console(orig_fgconsole); - release_console_sem(); - - if (vt_waitactive(orig_fgconsole)) { - pr_debug("Resume: Can't switch VCs."); - return; + if (orig_fgconsole >= 0) { + vt_move_to_console(orig_fgconsole, 0); + kmsg_redirect = orig_kmsg; } - - kmsg_redirect = orig_kmsg; } #endif diff --git a/kernel/resource.c b/kernel/resource.c index 78b087221c15..b94d6ff704cf 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -17,6 +17,7 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/device.h> +#include <linux/sched.h> #include <linux/pfn.h> #include <asm/io.h> @@ -592,6 +593,8 @@ resource_size_t resource_alignment(struct resource *res) * release_region releases a matching busy region. */ +static DECLARE_WAIT_QUEUE_HEAD(muxed_resource_wait); + /** * __request_region - create a new busy resource region * @parent: parent resource descriptor @@ -604,6 +607,7 @@ struct resource * __request_region(struct resource *parent, resource_size_t start, resource_size_t n, const char *name, int flags) { + DECLARE_WAITQUEUE(wait, current); struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL); if (!res) @@ -628,7 +632,14 @@ struct resource * __request_region(struct resource *parent, if (!(conflict->flags & IORESOURCE_BUSY)) continue; } - + if (conflict->flags & flags & IORESOURCE_MUXED) { + add_wait_queue(&muxed_resource_wait, &wait); + write_unlock(&resource_lock); + schedule(); + remove_wait_queue(&muxed_resource_wait, &wait); + write_lock(&resource_lock); + continue; + } /* Uhhuh, that didn't work out.. */ kfree(res); res = NULL; @@ -702,6 +713,8 @@ void __release_region(struct resource *parent, resource_size_t start, break; *p = res->sibling; write_unlock(&resource_lock); + if (res->flags & IORESOURCE_MUXED) + wake_up(&muxed_resource_wait); kfree(res); return; } |