]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
Merge branch 'rmobile/core' into rmobile-fixes-for-linus
authorPaul Mundt <lethal@linux-sh.org>
Mon, 15 Nov 2010 05:47:16 +0000 (14:47 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Mon, 15 Nov 2010 05:47:16 +0000 (14:47 +0900)
371 files changed:
Documentation/filesystems/Locking
Documentation/i2c/busses/i2c-i801
Documentation/scsi/ChangeLog.megaraid_sas
MAINTAINERS
Makefile
arch/arm/mach-u300/spi.c
arch/m68k/include/asm/irqflags.h
arch/m68k/include/asm/machdep.h
arch/powerpc/kernel/kvm.c
arch/powerpc/kvm/booke_interrupts.S
arch/powerpc/kvm/e500.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/kvm/timing.c
arch/sh/Kconfig
arch/sh/Makefile
arch/sh/boards/Kconfig
arch/sh/boards/Makefile
arch/sh/boards/board-edosk7705.c [new file with mode: 0644]
arch/sh/boards/board-secureedge5410.c [new file with mode: 0644]
arch/sh/boards/mach-edosk7705/Makefile [deleted file]
arch/sh/boards/mach-edosk7705/io.c [deleted file]
arch/sh/boards/mach-edosk7705/setup.c [deleted file]
arch/sh/boards/mach-microdev/io.c
arch/sh/boards/mach-microdev/setup.c
arch/sh/boards/mach-se/7206/Makefile
arch/sh/boards/mach-se/7206/io.c [deleted file]
arch/sh/boards/mach-se/7206/irq.c
arch/sh/boards/mach-se/7206/setup.c
arch/sh/boards/mach-se/770x/Makefile
arch/sh/boards/mach-se/770x/io.c [deleted file]
arch/sh/boards/mach-se/770x/setup.c
arch/sh/boards/mach-se/7751/Makefile
arch/sh/boards/mach-se/7751/io.c [deleted file]
arch/sh/boards/mach-se/7751/setup.c
arch/sh/boards/mach-snapgear/Makefile [deleted file]
arch/sh/boards/mach-snapgear/io.c [deleted file]
arch/sh/boards/mach-snapgear/setup.c [deleted file]
arch/sh/boards/mach-systemh/Makefile [deleted file]
arch/sh/boards/mach-systemh/io.c [deleted file]
arch/sh/boards/mach-systemh/irq.c [deleted file]
arch/sh/boards/mach-systemh/setup.c [deleted file]
arch/sh/configs/secureedge5410_defconfig [new file with mode: 0644]
arch/sh/configs/snapgear_defconfig [deleted file]
arch/sh/configs/systemh_defconfig [deleted file]
arch/sh/include/asm/addrspace.h
arch/sh/include/asm/pgtable.h
arch/sh/include/asm/system.h
arch/sh/include/asm/system_32.h
arch/sh/include/asm/system_64.h
arch/sh/include/asm/uncached.h
arch/sh/include/mach-common/mach/edosk7705.h [deleted file]
arch/sh/include/mach-common/mach/microdev.h
arch/sh/include/mach-common/mach/secureedge5410.h [new file with mode: 0644]
arch/sh/include/mach-common/mach/snapgear.h [deleted file]
arch/sh/include/mach-common/mach/systemh7751.h [deleted file]
arch/sh/kernel/cpu/sh4a/clock-sh7724.c
arch/sh/mm/Kconfig
arch/sh/mm/consistent.c
arch/sh/mm/uncached.c
arch/sh/tools/mach-types
arch/tile/include/asm/highmem.h
arch/tile/include/asm/kmap_types.h
arch/tile/include/asm/pgtable.h
arch/tile/include/asm/stat.h
arch/tile/include/asm/unistd.h
arch/tile/kernel/compat.c
arch/tile/kernel/early_printk.c
arch/tile/kernel/hardwall.c
arch/tile/kernel/irq.c
arch/tile/kernel/machine_kexec.c
arch/tile/kernel/messaging.c
arch/tile/kernel/ptrace.c
arch/tile/kernel/reboot.c
arch/tile/kernel/setup.c
arch/tile/kernel/signal.c
arch/tile/kernel/smp.c
arch/tile/kernel/time.c
arch/tile/lib/memcpy_tile64.c
arch/tile/mm/highmem.c
arch/tile/mm/init.c
arch/tile/mm/pgtable.c
arch/x86/kvm/mmu.c
arch/x86/kvm/x86.c
drivers/Makefile
drivers/block/floppy.c
drivers/char/.gitignore [deleted file]
drivers/char/Makefile
drivers/char/consolemap.c [deleted file]
drivers/char/cp437.uni [deleted file]
drivers/char/defkeymap.c_shipped [deleted file]
drivers/char/defkeymap.map [deleted file]
drivers/char/keyboard.c [deleted file]
drivers/char/n_gsm.c [deleted file]
drivers/char/n_hdlc.c [deleted file]
drivers/char/n_r3964.c [deleted file]
drivers/char/n_tty.c [deleted file]
drivers/char/pty.c [deleted file]
drivers/char/selection.c [deleted file]
drivers/char/sysrq.c [deleted file]
drivers/char/tty_audit.c [deleted file]
drivers/char/tty_buffer.c [deleted file]
drivers/char/tty_io.c [deleted file]
drivers/char/tty_ioctl.c [deleted file]
drivers/char/tty_ldisc.c [deleted file]
drivers/char/tty_mutex.c [deleted file]
drivers/char/tty_port.c [deleted file]
drivers/char/vc_screen.c [deleted file]
drivers/char/vt.c [deleted file]
drivers/char/vt_ioctl.c [deleted file]
drivers/firewire/ohci.c
drivers/hwmon/ltc4261.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-i801.c
drivers/input/mouse/appletouch.c
drivers/input/touchscreen/ad7879.c
drivers/input/touchscreen/bu21013_ts.c
drivers/isdn/hisax/isar.c
drivers/leds/leds-net5501.c
drivers/media/IR/ir-keytable.c
drivers/net/atlx/atl1.c
drivers/net/bnx2x/bnx2x.h
drivers/net/bnx2x/bnx2x_hsi.h
drivers/net/bnx2x/bnx2x_link.c
drivers/net/caif/caif_spi.c
drivers/net/caif/caif_spi_slave.c
drivers/net/cxgb3/cxgb3_main.c
drivers/net/cxgb4/cxgb4_main.c
drivers/net/cxgb4vf/cxgb4vf_main.c
drivers/net/ibm_newemac/core.c
drivers/net/jme.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/qlcnic/qlcnic_main.c
drivers/net/smsc911x.h
drivers/net/tulip/de2104x.c
drivers/net/usb/usbnet.c
drivers/net/wireless/ipw2x00/libipw_module.c
drivers/rtc/rtc-ds1302.c
drivers/s390/scsi/zfcp_fc.h
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_unit.c
drivers/scsi/bfa/bfa.h
drivers/scsi/bfa/bfa_cb_ioim.h
drivers/scsi/bfa/bfa_core.c
drivers/scsi/bfa/bfa_cs.h
drivers/scsi/bfa/bfa_defs.h
drivers/scsi/bfa/bfa_defs_fcs.h
drivers/scsi/bfa/bfa_defs_svc.h
drivers/scsi/bfa/bfa_drv.c
drivers/scsi/bfa/bfa_fc.h
drivers/scsi/bfa/bfa_fcbuild.c
drivers/scsi/bfa/bfa_fcpim.c
drivers/scsi/bfa/bfa_fcpim.h
drivers/scsi/bfa/bfa_fcs.c
drivers/scsi/bfa/bfa_fcs.h
drivers/scsi/bfa/bfa_fcs_fcpim.c
drivers/scsi/bfa/bfa_fcs_lport.c
drivers/scsi/bfa/bfa_fcs_rport.c
drivers/scsi/bfa/bfa_hw_cb.c
drivers/scsi/bfa/bfa_hw_ct.c
drivers/scsi/bfa/bfa_ioc.c
drivers/scsi/bfa/bfa_ioc.h
drivers/scsi/bfa/bfa_ioc_cb.c
drivers/scsi/bfa/bfa_ioc_ct.c
drivers/scsi/bfa/bfa_modules.h
drivers/scsi/bfa/bfa_os_inc.h
drivers/scsi/bfa/bfa_port.c
drivers/scsi/bfa/bfa_svc.c
drivers/scsi/bfa/bfa_svc.h
drivers/scsi/bfa/bfad.c
drivers/scsi/bfa/bfad_attr.c
drivers/scsi/bfa/bfad_debugfs.c
drivers/scsi/bfa/bfad_drv.h
drivers/scsi/bfa/bfad_im.c
drivers/scsi/bfa/bfi.h
drivers/scsi/bfa/bfi_ms.h
drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
drivers/scsi/device_handler/scsi_dh_rdac.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/fcoe/libfcoe.c
drivers/scsi/gdth.c
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/libfc/fc_disc.c
drivers/scsi/libfc/fc_fcp.c
drivers/scsi/libfc/fc_lport.c
drivers/scsi/libfc/fc_rport.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_bsg.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_hw4.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli4.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/megaraid/megaraid_sas.c
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/osd/osd_initiator.c
drivers/scsi/pmcraid.c
drivers/scsi/pmcraid.h
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_bsg.c
drivers/scsi/qla2xxx/qla_bsg.h
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla4xxx/ql4_dbg.c
drivers/scsi/qla4xxx/ql4_def.h
drivers/scsi/qla4xxx/ql4_fw.h
drivers/scsi/qla4xxx/ql4_glbl.h
drivers/scsi/qla4xxx/ql4_init.c
drivers/scsi/qla4xxx/ql4_iocb.c
drivers/scsi/qla4xxx/ql4_isr.c
drivers/scsi/qla4xxx/ql4_mbx.c
drivers/scsi/qla4xxx/ql4_nx.c
drivers/scsi/qla4xxx/ql4_nx.h
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/qla4xxx/ql4_version.h
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/sd.c
drivers/scsi/sr_ioctl.c
drivers/serial/crisv10.c
drivers/sh/clk/core.c
drivers/sh/intc/core.c
drivers/sh/intc/dynamic.c
drivers/spi/spi.c
drivers/spi/spi_bfin5xx.c
drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c
drivers/staging/ath6kl/os/linux/ar6000_raw_if.c
drivers/staging/ath6kl/os/linux/include/athendpack_linux.h [deleted file]
drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h [deleted file]
drivers/staging/brcm80211/brcmfmac/dhd_linux.c
drivers/staging/brcm80211/sys/wl_mac80211.c
drivers/staging/comedi/drivers/dt9812.c
drivers/staging/comedi/drivers/usbdux.c
drivers/staging/comedi/drivers/usbduxfast.c
drivers/staging/msm/msm_fb.c
drivers/staging/rtl8712/osdep_service.h
drivers/staging/smbfs/inode.c
drivers/staging/solo6x10/solo6010-v4l2-enc.c
drivers/staging/solo6x10/solo6010-v4l2.c
drivers/staging/tm6000/tm6000-i2c.c
drivers/staging/westbridge/astoria/block/cyasblkdev_block.c
drivers/staging/westbridge/astoria/block/cyasblkdev_queue.c
drivers/tty/Makefile [new file with mode: 0644]
drivers/tty/n_gsm.c [new file with mode: 0644]
drivers/tty/n_hdlc.c [new file with mode: 0644]
drivers/tty/n_r3964.c [new file with mode: 0644]
drivers/tty/n_tty.c [new file with mode: 0644]
drivers/tty/pty.c [new file with mode: 0644]
drivers/tty/sysrq.c [new file with mode: 0644]
drivers/tty/tty_audit.c [new file with mode: 0644]
drivers/tty/tty_buffer.c [new file with mode: 0644]
drivers/tty/tty_io.c [new file with mode: 0644]
drivers/tty/tty_ioctl.c [new file with mode: 0644]
drivers/tty/tty_ldisc.c [new file with mode: 0644]
drivers/tty/tty_mutex.c [new file with mode: 0644]
drivers/tty/tty_port.c [new file with mode: 0644]
drivers/tty/vt/.gitignore [new file with mode: 0644]
drivers/tty/vt/Makefile [new file with mode: 0644]
drivers/tty/vt/consolemap.c [new file with mode: 0644]
drivers/tty/vt/cp437.uni [new file with mode: 0644]
drivers/tty/vt/defkeymap.c_shipped [new file with mode: 0644]
drivers/tty/vt/defkeymap.map [new file with mode: 0644]
drivers/tty/vt/keyboard.c [new file with mode: 0644]
drivers/tty/vt/selection.c [new file with mode: 0644]
drivers/tty/vt/vc_screen.c [new file with mode: 0644]
drivers/tty/vt/vt.c [new file with mode: 0644]
drivers/tty/vt/vt_ioctl.c [new file with mode: 0644]
drivers/usb/gadget/u_ether.c
fs/cifs/TODO
fs/cifs/cifs_fs_sb.h
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/ioctl.c
fs/cifs/misc.c
fs/ext4/ext4.h
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/page-io.c
fs/ext4/super.c
fs/gfs2/file.c
fs/hpfs/buffer.c
fs/hpfs/hpfs_fn.h
fs/hpfs/super.c
fs/jbd2/journal.c
fs/locks.c
fs/logfs/logfs.h
fs/nfs/file.c
fs/nfsd/nfs4state.c
include/asm-generic/stat.h
include/linux/fs.h
include/linux/hardirq.h
include/linux/i2c.h
include/linux/irq.h
include/linux/irqnr.h
include/linux/pci_ids.h
include/linux/semaphore.h
include/linux/sh_clk.h
include/linux/spi/spi.h
include/net/caif/caif_dev.h
include/net/caif/caif_spi.h
include/net/caif/cfcnfg.h
include/net/netlink.h
include/scsi/libfc.h
include/scsi/osd_initiator.h
include/scsi/osd_protocol.h
include/scsi/osd_types.h
include/trace/events/ext4.h
kernel/exit.c
kernel/irq/manage.c
kernel/relay.c
kernel/watchdog.c
mm/filemap.c
mm/vmstat.c
net/caif/caif_config_util.c
net/caif/caif_dev.c
net/caif/caif_socket.c
net/caif/cfcnfg.c
net/caif/cfctrl.c
net/caif/cfdbgl.c
net/caif/cfrfml.c
net/core/dev.c
net/ipv4/fib_lookup.h
net/ipv4/inet_diag.c
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/nf_nat_core.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/route.c
net/l2tp/l2tp_debugfs.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_proto.c
net/rds/loop.c
net/rds/tcp.c
net/sched/cls_cgroup.c
net/sched/em_text.c
net/x25/x25_facilities.c
net/x25/x25_in.c
scripts/checkpatch.pl
scripts/kconfig/symbol.c
sound/pci/asihpi/hpi6000.c
sound/pci/asihpi/hpi6205.c
sound/pci/asihpi/hpicmn.c
sound/pci/cs46xx/dsp_spos.c
sound/pci/hda/patch_cirrus.c
sound/pci/lx6464es/lx6464es.c
sound/pci/lx6464es/lx6464es.h
sound/pci/lx6464es/lx_core.c
sound/soc/codecs/Kconfig
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/tpa6130a2.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm_hubs.c
sound/soc/pxa/tosa.c
sound/soc/soc-core.c
sound/usb/mixer_quirks.c
sound/usb/pcm.c
usr/initramfs_data.S

index 8a817f656f0a808dffb344c6a46bab960cb8a0ae..a91f30890011ddf69ba9b859484966c943db7fb5 100644 (file)
@@ -322,7 +322,6 @@ fl_release_private: yes     yes
 prototypes:
        int (*fl_compare_owner)(struct file_lock *, struct file_lock *);
        void (*fl_notify)(struct file_lock *);  /* unblock callback */
-       void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
        void (*fl_release_private)(struct file_lock *);
        void (*fl_break)(struct file_lock *); /* break_lease callback */
 
@@ -330,7 +329,6 @@ locking rules:
                        BKL     may block
 fl_compare_owner:      yes     no
 fl_notify:             yes     no
-fl_copy_lock:          yes     no
 fl_release_private:    yes     yes
 fl_break:              yes     no
 
index e307914a3edafc84c2019911d48b9922133e7812..93fe76e56522a199a0ab5044544673418be64ec0 100644 (file)
@@ -15,10 +15,14 @@ Supported adapters:
   * Intel 82801I (ICH9)
   * Intel EP80579 (Tolapai)
   * Intel 82801JI (ICH10)
-  * Intel 3400/5 Series (PCH)
+  * Intel 5/3400 Series (PCH)
   * Intel Cougar Point (PCH)
+  * Intel Patsburg (PCH)
    Datasheets: Publicly available at the Intel website
 
+On Intel Patsburg and later chipsets, both the normal host SMBus controller
+and the additional 'Integrated Device Function' controllers are supported.
+
 Authors: 
        Mark Studebaker <mdsxyz123@yahoo.com>
        Jean Delvare <khali@linux-fr.org>
index 30023568805e2a56077fa4cfbd088ee666522ab0..00301ed9c3715596b35411f46ff31243412444dd 100644 (file)
@@ -1,3 +1,50 @@
+1 Release Date    : Thur.  May 03, 2010 09:12:45 PST 2009 -
+                       (emaild-id:megaraidlinux@lsi.com)
+                       Bo Yang
+
+2 Current Version : 00.00.04.31-rc1
+3 Older Version   : 00.00.04.17.1-rc1
+
+1.     Add the Online Controller Reset (OCR) to the Driver.
+       OCR is the new feature for megaraid_sas driver which
+       will allow the fw to do the chip reset which will not
+       affact the OS behavious.
+
+       To add the OCR support, driver need to do:
+               a). reset the controller chips -- Xscale and Gen2 which
+               will change the function calls and add the reset function
+               related to this two chips.
+
+               b). during the reset, driver will store the pending cmds
+               which not returned by FW to driver's pending queue.  Driver
+               will re-issue those pending cmds again to FW after the OCR
+               finished.
+
+               c). In driver's timeout routine, driver will report to
+               OS as reset. Also driver's queue routine will block the
+               cmds until the OCR finished.
+
+               d). in Driver's ISR routine, if driver get the FW state as
+               state change, FW in Failure status and FW support online controller
+               reset (OCR), driver will start to do the controller reset.
+
+               e). In driver's IOCTL routine, the application cmds will wait for the
+               OCR to finish, then issue the cmds to FW.
+
+               f). Before driver kill adapter, driver will do last chance of
+               OCR to see if driver can bring back the FW.
+
+2.     Add the support update flag to the driver to tell LSI megaraid_sas
+       application which driver will support the device update.  So application
+       will not need to do the device update after application add/del the device
+       from the system.
+3.     In driver's timeout routine, driver will do three time reset if fw is in
+       failed state.  Driver will kill adapter if can't bring back FW after the
+       this three times reset.
+4.     Add the input parameter max_sectors to 1MB support to our GEN2 controller.
+       customer can use the input paramenter max_sectors to add 1MB support to GEN2
+       controller.
+
 1 Release Date    : Thur.  Oct 29, 2009 09:12:45 PST 2009 -
                        (emaild-id:megaraidlinux@lsi.com)
                        Bo Yang
index cb8b580203524baa077ee0bea390efb3d559c4c4..f5ec964865c7edf553cf1b60129b40b3f18bf0b2 100644 (file)
@@ -945,7 +945,7 @@ M:  Magnus Damm <magnus.damm@gmail.com>
 L:     linux-sh@vger.kernel.org
 W:     http://oss.renesas.com
 Q:     http://patchwork.kernel.org/project/linux-sh/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/genesis-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6.git rmobile-latest
 S:     Supported
 F:     arch/arm/mach-shmobile/
 F:     drivers/sh/
@@ -1757,6 +1757,7 @@ L:        linux-cris-kernel@axis.com
 W:     http://developer.axis.com
 S:     Maintained
 F:     arch/cris/
+F:     drivers/serial/crisv10.*
 
 CRYPTO API
 M:     Herbert Xu <herbert@gondor.apana.org.au>
index 519db43052a047f175501cca984d8058cf382b1c..6619720f50dd667abf746f1dd892b35c67a9742c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
-SUBLEVEL = 36
-EXTRAVERSION =
+SUBLEVEL = 37
+EXTRAVERSION = -rc1
 NAME = Flesh-Eating Bats with Fangs
 
 # *DOCUMENTATION*
index edb2c0d255c2a1671cae12e6704da28e6b66cb8d..00869def54205c3291b44eafacf3afba7eb03d68 100644 (file)
@@ -67,7 +67,7 @@ static struct spi_board_info u300_spi_devices[] = {
                .bus_num        = 0, /* Only one bus on this chip */
                .chip_select    = 0,
                /* Means SPI_CS_HIGH, change if e.g low CS */
-               .mode           = SPI_MODE_1 | SPI_LSB_FIRST | SPI_LOOP,
+               .mode           = SPI_MODE_1 | SPI_LOOP,
        },
 #endif
 };
index 4a5b284a15500f4a1a8525dab1609d34310599c0..7ef4115b8c4a59f0248df2273184ab5e2ed8f053 100644 (file)
@@ -2,7 +2,9 @@
 #define _M68K_IRQFLAGS_H
 
 #include <linux/types.h>
+#ifdef CONFIG_MMU
 #include <linux/hardirq.h>
+#endif
 #include <linux/preempt.h>
 #include <asm/thread_info.h>
 #include <asm/entry.h>
index 789f3b2de0e9bf2f63720bcc0c522c686e9c9d31..415d5484916c4d9e6ec1981e380cfe9a0f1ab4de 100644 (file)
@@ -40,5 +40,6 @@ extern unsigned long hw_timer_offset(void);
 extern irqreturn_t arch_timer_interrupt(int irq, void *dummy);
 
 extern void config_BSP(char *command, int len);
+extern void do_IRQ(int irq, struct pt_regs *fp);
 
 #endif /* _M68K_MACHDEP_H */
index 428d0e538aec50880f23b8b097698572a2d2a01a..b06bdae04064f59d2c4c4c98e76304dee6ca98c8 100644 (file)
@@ -127,7 +127,7 @@ static void kvm_patch_ins_nop(u32 *inst)
 
 static void kvm_patch_ins_b(u32 *inst, int addr)
 {
-#ifdef CONFIG_RELOCATABLE
+#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_PPC_BOOK3S)
        /* On relocatable kernels interrupts handlers and our code
           can be in different regions, so we don't patch them */
 
index 049846911ce4d18d8097507b9be0caa8d767733c..1cc471faac2dd4bac032a956860b4f10d29170cb 100644 (file)
@@ -416,7 +416,7 @@ lightweight_exit:
        lwz     r3, VCPU_PC(r4)
        mtsrr0  r3
        lwz     r3, VCPU_SHARED(r4)
-       lwz     r3, VCPU_SHARED_MSR(r3)
+       lwz     r3, (VCPU_SHARED_MSR + 4)(r3)
        oris    r3, r3, KVMPPC_MSR_MASK@h
        ori     r3, r3, KVMPPC_MSR_MASK@l
        mtsrr1  r3
index 71750f2dd5d34378c963acf7bf9d3a69a15863cc..e3768ee9b59537bf92eceb853fa9edf56d7d5b6c 100644 (file)
@@ -138,8 +138,8 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
 
        free_page((unsigned long)vcpu->arch.shared);
-       kvmppc_e500_tlb_uninit(vcpu_e500);
        kvm_vcpu_uninit(vcpu);
+       kvmppc_e500_tlb_uninit(vcpu_e500);
        kmem_cache_free(kvm_vcpu_cache, vcpu_e500);
 }
 
index 2f87a1627f6cff35604f96e8e041cffd9af071ff..38f756f2505389ac5f59eb9ae3921ef72175eea1 100644 (file)
@@ -617,6 +617,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
        switch (ioctl) {
        case KVM_PPC_GET_PVINFO: {
                struct kvm_ppc_pvinfo pvinfo;
+               memset(&pvinfo, 0, sizeof(pvinfo));
                r = kvm_vm_ioctl_get_pvinfo(&pvinfo);
                if (copy_to_user(argp, &pvinfo, sizeof(pvinfo))) {
                        r = -EFAULT;
index 46fa04f12a9b979c7cbe50c703d43e2c2705604e..a021f5827a336ce97b6c62ed5b8d0ca625d571bf 100644 (file)
@@ -35,7 +35,6 @@ void kvmppc_init_timing_stats(struct kvm_vcpu *vcpu)
        int i;
 
        /* pause guest execution to avoid concurrent updates */
-       local_irq_disable();
        mutex_lock(&vcpu->mutex);
 
        vcpu->arch.last_exit_type = 0xDEAD;
@@ -51,7 +50,6 @@ void kvmppc_init_timing_stats(struct kvm_vcpu *vcpu)
        vcpu->arch.timing_last_enter.tv64 = 0;
 
        mutex_unlock(&vcpu->mutex);
-       local_irq_enable();
 }
 
 static void add_exit_timing(struct kvm_vcpu *vcpu, u64 duration, int type)
index 5c075f562ebae912476974f20faee1bfaeec707d..7f217b3a50a806b7347f991b588397011aa3388e 100644 (file)
@@ -193,6 +193,7 @@ config CPU_SH2
 config CPU_SH2A
        bool
        select CPU_SH2
+       select UNCACHED_MAPPING
 
 config CPU_SH3
        bool
index 307b3a4a790b98b61bd3cb893dfa155ff4983e0b..9c8c6e1a2a154d4dff50db8d0d532201c5f991be 100644 (file)
@@ -133,10 +133,7 @@ machdir-$(CONFIG_SOLUTION_ENGINE)          += mach-se
 machdir-$(CONFIG_SH_HP6XX)                     += mach-hp6xx
 machdir-$(CONFIG_SH_DREAMCAST)                 += mach-dreamcast
 machdir-$(CONFIG_SH_SH03)                      += mach-sh03
-machdir-$(CONFIG_SH_SECUREEDGE5410)            += mach-snapgear
 machdir-$(CONFIG_SH_RTS7751R2D)                        += mach-r2d
-machdir-$(CONFIG_SH_7751_SYSTEMH)              += mach-systemh
-machdir-$(CONFIG_SH_EDOSK7705)                 += mach-edosk7705
 machdir-$(CONFIG_SH_HIGHLANDER)                        += mach-highlander
 machdir-$(CONFIG_SH_MIGOR)                     += mach-migor
 machdir-$(CONFIG_SH_AP325RXA)                  += mach-ap325rxa
index 9c94711aa6caee785b152ba7be282b98a6b6d285..2018c7ea4c93f49d53d7f1ff82f32db2b85e85bc 100644 (file)
@@ -81,13 +81,6 @@ config SH_7343_SOLUTION_ENGINE
          Select 7343 SolutionEngine if configuring for a Hitachi
          SH7343 (SH-Mobile 3AS) evaluation board.
 
-config SH_7751_SYSTEMH
-       bool "SystemH7751R"
-       depends on CPU_SUBTYPE_SH7751R
-       help
-         Select SystemH if you are configuring for a Renesas SystemH
-         7751R evaluation board.
-
 config SH_HP6XX
        bool "HP6XX"
        select SYS_SUPPORTS_APM_EMULATION
index 38ef655cc0f08cfe0f881b053f421e9861412556..be7d11d04b26a3abcaeacde829e496f970903c33 100644 (file)
@@ -2,10 +2,12 @@
 # Specific board support, not covered by a mach group.
 #
 obj-$(CONFIG_SH_MAGIC_PANEL_R2)        += board-magicpanelr2.o
+obj-$(CONFIG_SH_SECUREEDGE5410)        += board-secureedge5410.o
 obj-$(CONFIG_SH_SH2007)                += board-sh2007.o
 obj-$(CONFIG_SH_SH7785LCR)     += board-sh7785lcr.o
 obj-$(CONFIG_SH_URQUELL)       += board-urquell.o
 obj-$(CONFIG_SH_SHMIN)         += board-shmin.o
+obj-$(CONFIG_SH_EDOSK7705)     += board-edosk7705.o
 obj-$(CONFIG_SH_EDOSK7760)     += board-edosk7760.o
 obj-$(CONFIG_SH_ESPT)          += board-espt.o
 obj-$(CONFIG_SH_POLARIS)       += board-polaris.o
diff --git a/arch/sh/boards/board-edosk7705.c b/arch/sh/boards/board-edosk7705.c
new file mode 100644 (file)
index 0000000..4cb3bb7
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * arch/sh/boards/renesas/edosk7705/setup.c
+ *
+ * Copyright (C) 2000  Kazumoto Kojima
+ *
+ * Hitachi SolutionEngine Support.
+ *
+ * Modified for edosk7705 development
+ * board by S. Dunn, 2003.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/smc91x.h>
+#include <asm/machvec.h>
+#include <asm/sizes.h>
+
+#define SMC_IOBASE     0xA2000000
+#define SMC_IO_OFFSET  0x300
+#define SMC_IOADDR     (SMC_IOBASE + SMC_IO_OFFSET)
+
+#define ETHERNET_IRQ   0x09
+
+static void __init sh_edosk7705_init_irq(void)
+{
+       make_imask_irq(ETHERNET_IRQ);
+}
+
+/* eth initialization functions */
+static struct smc91x_platdata smc91x_info = {
+       .flags = SMC91X_USE_16BIT | SMC91X_IO_SHIFT_1 | IORESOURCE_IRQ_LOWLEVEL,
+};
+
+static struct resource smc91x_res[] = {
+       [0] = {
+               .start  = SMC_IOADDR,
+               .end    = SMC_IOADDR + SZ_32 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = ETHERNET_IRQ,
+               .end    = ETHERNET_IRQ,
+               .flags  = IORESOURCE_IRQ ,
+       }
+};
+
+static struct platform_device smc91x_dev = {
+       .name           = "smc91x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(smc91x_res),
+       .resource       = smc91x_res,
+
+       .dev    = {
+               .platform_data  = &smc91x_info,
+       },
+};
+
+/* platform init code */
+static struct platform_device *edosk7705_devices[] __initdata = {
+       &smc91x_dev,
+};
+
+static int __init init_edosk7705_devices(void)
+{
+       return platform_add_devices(edosk7705_devices,
+                                   ARRAY_SIZE(edosk7705_devices));
+}
+__initcall(init_edosk7705_devices);
+
+/*
+ * The Machine Vector
+ */
+static struct sh_machine_vector mv_edosk7705 __initmv = {
+       .mv_name                = "EDOSK7705",
+       .mv_nr_irqs             = 80,
+       .mv_init_irq            = sh_edosk7705_init_irq,
+};
diff --git a/arch/sh/boards/board-secureedge5410.c b/arch/sh/boards/board-secureedge5410.c
new file mode 100644 (file)
index 0000000..32f875e
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2002  David McCullough <davidm@snapgear.com>
+ * Copyright (C) 2003  Paul Mundt <lethal@linux-sh.org>
+ *
+ * Based on files with the following comments:
+ *
+ *           Copyright (C) 2000  Kazumoto Kojima
+ *
+ *           Modified for 7751 Solution Engine by
+ *           Ian da Silva and Jeremy Siegel, 2001.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <asm/machvec.h>
+#include <mach/secureedge5410.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <cpu/timer.h>
+
+unsigned short secureedge5410_ioport;
+
+/*
+ * EraseConfig handling functions
+ */
+static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id)
+{
+       ctrl_delay();   /* dummy read */
+
+       printk("SnapGear: erase switch interrupt!\n");
+
+       return IRQ_HANDLED;
+}
+
+static int __init eraseconfig_init(void)
+{
+       unsigned int irq = evt2irq(0x240);
+
+       printk("SnapGear: EraseConfig init\n");
+
+       /* Setup "EraseConfig" switch on external IRQ 0 */
+       if (request_irq(irq, eraseconfig_interrupt, IRQF_DISABLED,
+                               "Erase Config", NULL))
+               printk("SnapGear: failed to register IRQ%d for Reset witch\n",
+                               irq);
+       else
+               printk("SnapGear: registered EraseConfig switch on IRQ%d\n",
+                               irq);
+       return 0;
+}
+module_init(eraseconfig_init);
+
+/*
+ * Initialize IRQ setting
+ *
+ * IRL0 = erase switch
+ * IRL1 = eth0
+ * IRL2 = eth1
+ * IRL3 = crypto
+ */
+static void __init init_snapgear_IRQ(void)
+{
+       printk("Setup SnapGear IRQ/IPR ...\n");
+       /* enable individual interrupt mode for externals */
+       plat_irq_setup_pins(IRQ_MODE_IRQ);
+}
+
+/*
+ * The Machine Vector
+ */
+static struct sh_machine_vector mv_snapgear __initmv = {
+       .mv_name                = "SnapGear SecureEdge5410",
+       .mv_nr_irqs             = 72,
+       .mv_init_irq            = init_snapgear_IRQ,
+};
diff --git a/arch/sh/boards/mach-edosk7705/Makefile b/arch/sh/boards/mach-edosk7705/Makefile
deleted file mode 100644 (file)
index cd54acb..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the EDOSK7705 specific parts of the kernel
-#
-
-obj-y   := setup.o io.o
diff --git a/arch/sh/boards/mach-edosk7705/io.c b/arch/sh/boards/mach-edosk7705/io.c
deleted file mode 100644 (file)
index 5b9c57c..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * arch/sh/boards/renesas/edosk7705/io.c
- *
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routines for Hitachi EDOSK7705 board.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/io.h>
-#include <mach/edosk7705.h>
-#include <asm/addrspace.h>
-
-#define SMC_IOADDR     0xA2000000
-
-/* Map the Ethernet addresses as if it is at 0x300 - 0x320 */
-static unsigned long sh_edosk7705_isa_port2addr(unsigned long port)
-{
-       /*
-        * SMC91C96 registers are 4 byte aligned rather than the
-        * usual 2 byte!
-        */
-       if (port >= 0x300 && port < 0x320)
-               return SMC_IOADDR + ((port - 0x300) * 2);
-
-       maybebadio(port);
-       return port;
-}
-
-/* Trying to read / write bytes on odd-byte boundaries to the Ethernet
- * registers causes problems. So we bit-shift the value and read / write
- * in 2 byte chunks. Setting the low byte to 0 does not cause problems
- * now as odd byte writes are only made on the bit mask / interrupt
- * register. This may not be the case in future Mar-2003 SJD
- */
-unsigned char sh_edosk7705_inb(unsigned long port)
-{
-       if (port >= 0x300 && port < 0x320 && port & 0x01)
-               return __raw_readw(port - 1) >> 8;
-
-       return __raw_readb(sh_edosk7705_isa_port2addr(port));
-}
-
-void sh_edosk7705_outb(unsigned char value, unsigned long port)
-{
-       if (port >= 0x300 && port < 0x320 && port & 0x01) {
-               __raw_writew(((unsigned short)value << 8), port - 1);
-               return;
-       }
-
-       __raw_writeb(value, sh_edosk7705_isa_port2addr(port));
-}
-
-void sh_edosk7705_insb(unsigned long port, void *addr, unsigned long count)
-{
-       unsigned char *p = addr;
-
-       while (count--)
-               *p++ = sh_edosk7705_inb(port);
-}
-
-void sh_edosk7705_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       unsigned char *p = (unsigned char *)addr;
-
-       while (count--)
-               sh_edosk7705_outb(*p++, port);
-}
diff --git a/arch/sh/boards/mach-edosk7705/setup.c b/arch/sh/boards/mach-edosk7705/setup.c
deleted file mode 100644 (file)
index d59225e..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * arch/sh/boards/renesas/edosk7705/setup.c
- *
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * Hitachi SolutionEngine Support.
- *
- * Modified for edosk7705 development
- * board by S. Dunn, 2003.
- */
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <asm/machvec.h>
-#include <mach/edosk7705.h>
-
-static void __init sh_edosk7705_init_irq(void)
-{
-       /* This is the Ethernet interrupt */
-       make_imask_irq(0x09);
-}
-
-/*
- * The Machine Vector
- */
-static struct sh_machine_vector mv_edosk7705 __initmv = {
-       .mv_name                = "EDOSK7705",
-       .mv_nr_irqs             = 80,
-
-       .mv_inb                 = sh_edosk7705_inb,
-       .mv_outb                = sh_edosk7705_outb,
-
-       .mv_insb                = sh_edosk7705_insb,
-       .mv_outsb               = sh_edosk7705_outsb,
-
-       .mv_init_irq            = sh_edosk7705_init_irq,
-};
index 2960c659020ee92e6c60c5c1d16d8d05ab73e267..acdafb0c6404a153cc482e46c0a17287f15ea26e 100644 (file)
@@ -54,7 +54,7 @@
 /*
  * map I/O ports to memory-mapped addresses
  */
-static unsigned long microdev_isa_port2addr(unsigned long offset)
+void __iomem *microdev_ioport_map(unsigned long offset, unsigned int len)
 {
        unsigned long result;
 
@@ -72,16 +72,6 @@ static unsigned long microdev_isa_port2addr(unsigned long offset)
                         *      Configuration Registers
                         */
                result = IO_SUPERIO_PHYS + (offset << 1);
-#if 0
-       } else if (offset == KBD_DATA_REG || offset == KBD_CNTL_REG ||
-                  offset == KBD_STATUS_REG) {
-                       /*
-                        *      SMSC FDC37C93xAPM SuperIO chip
-                        *
-                        *      PS/2 Keyboard + Mouse (ports 0x60 and 0x64).
-                        */
-               result = IO_SUPERIO_PHYS + (offset << 1);
-#endif
        } else if (((offset >= IO_IDE1_BASE) &&
                    (offset <  IO_IDE1_BASE + IO_IDE_EXTENT)) ||
                    (offset == IO_IDE1_MISC)) {
@@ -131,237 +121,5 @@ static unsigned long microdev_isa_port2addr(unsigned long offset)
                result = PVR;
        }
 
-       return result;
-}
-
-#define PORT2ADDR(x) (microdev_isa_port2addr(x))
-
-static inline void delay(void)
-{
-#if defined(CONFIG_PCI)
-       /* System board present, just make a dummy SRAM access.  (CS0 will be
-          mapped to PCI memory, probably good to avoid it.) */
-       __raw_readw(0xa6800000);
-#else
-       /* CS0 will be mapped to flash, ROM etc so safe to access it. */
-       __raw_readw(0xa0000000);
-#endif
-}
-
-unsigned char microdev_inb(unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO)
-               return microdev_pci_inb(port);
-#endif
-       return *(volatile unsigned char*)PORT2ADDR(port);
-}
-
-unsigned short microdev_inw(unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO)
-               return microdev_pci_inw(port);
-#endif
-       return *(volatile unsigned short*)PORT2ADDR(port);
-}
-
-unsigned int microdev_inl(unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO)
-               return microdev_pci_inl(port);
-#endif
-       return *(volatile unsigned int*)PORT2ADDR(port);
-}
-
-void microdev_outw(unsigned short b, unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO) {
-               microdev_pci_outw(b, port);
-               return;
-       }
-#endif
-       *(volatile unsigned short*)PORT2ADDR(port) = b;
-}
-
-void microdev_outb(unsigned char b, unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO) {
-               microdev_pci_outb(b, port);
-               return;
-       }
-#endif
-
-       /*
-        *      There is a board feature with the current SH4-202 MicroDev in
-        *      that the 2 byte enables (nBE0 and nBE1) are tied together (and
-        *      to the Chip Select Line (Ethernet_CS)). Due to this connectivity,
-        *      it is not possible to safely perform 8-bit writes to the
-        *      Ethernet registers, as 16-bits will be consumed from the Data
-        *      lines (corrupting the other byte).  Hence, this function is
-        *      written to implement 16-bit read/modify/write for all byte-wide
-        *      accesses.
-        *
-        *      Note: there is no problem with byte READS (even or odd).
-        *
-        *                      Sean McGoogan - 16th June 2003.
-        */
-       if ((port >= IO_LAN91C111_BASE) &&
-           (port <  IO_LAN91C111_BASE + IO_LAN91C111_EXTENT)) {
-                       /*
-                        * Then are trying to perform a byte-write to the
-                        * LAN91C111.  This needs special care.
-                        */
-               if (port % 2 == 1) {    /* is the port odd ? */
-                       /* unset bit-0, i.e. make even */
-                       const unsigned long evenPort = port-1;
-                       unsigned short word;
-
-                       /*
-                        * do a 16-bit read/write to write to 'port',
-                        * preserving even byte.
-                        *
-                        *      Even addresses are bits 0-7
-                        *      Odd  addresses are bits 8-15
-                        */
-                       word = microdev_inw(evenPort);
-                       word = (word & 0xffu) | (b << 8);
-                       microdev_outw(word, evenPort);
-               } else {
-                       /* else, we are trying to do an even byte write */
-                       unsigned short word;
-
-                       /*
-                        * do a 16-bit read/write to write to 'port',
-                        * preserving odd byte.
-                        *
-                        *      Even addresses are bits 0-7
-                        *      Odd  addresses are bits 8-15
-                        */
-                       word = microdev_inw(port);
-                       word = (word & 0xff00u) | (b);
-                       microdev_outw(word, port);
-               }
-       } else {
-               *(volatile unsigned char*)PORT2ADDR(port) = b;
-       }
-}
-
-void microdev_outl(unsigned int b, unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO) {
-               microdev_pci_outl(b, port);
-               return;
-       }
-#endif
-       *(volatile unsigned int*)PORT2ADDR(port) = b;
-}
-
-unsigned char microdev_inb_p(unsigned long port)
-{
-       unsigned char v = microdev_inb(port);
-       delay();
-       return v;
-}
-
-unsigned short microdev_inw_p(unsigned long port)
-{
-       unsigned short v = microdev_inw(port);
-       delay();
-       return v;
-}
-
-unsigned int microdev_inl_p(unsigned long port)
-{
-       unsigned int v = microdev_inl(port);
-       delay();
-       return v;
-}
-
-void microdev_outb_p(unsigned char b, unsigned long port)
-{
-       microdev_outb(b, port);
-       delay();
-}
-
-void microdev_outw_p(unsigned short b, unsigned long port)
-{
-       microdev_outw(b, port);
-       delay();
-}
-
-void microdev_outl_p(unsigned int b, unsigned long port)
-{
-       microdev_outl(b, port);
-       delay();
-}
-
-void microdev_insb(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned char *port_addr;
-       unsigned char *buf = buffer;
-
-       port_addr = (volatile unsigned char *)PORT2ADDR(port);
-
-       while (count--)
-               *buf++ = *port_addr;
-}
-
-void microdev_insw(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned short *port_addr;
-       unsigned short *buf = buffer;
-
-       port_addr = (volatile unsigned short *)PORT2ADDR(port);
-
-       while (count--)
-               *buf++ = *port_addr;
-}
-
-void microdev_insl(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned long *port_addr;
-       unsigned int *buf = buffer;
-
-       port_addr = (volatile unsigned long *)PORT2ADDR(port);
-
-       while (count--)
-               *buf++ = *port_addr;
-}
-
-void microdev_outsb(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned char *port_addr;
-       const unsigned char *buf = buffer;
-
-       port_addr = (volatile unsigned char *)PORT2ADDR(port);
-
-       while (count--)
-               *port_addr = *buf++;
-}
-
-void microdev_outsw(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned short *port_addr;
-       const unsigned short *buf = buffer;
-
-       port_addr = (volatile unsigned short *)PORT2ADDR(port);
-
-       while (count--)
-               *port_addr = *buf++;
-}
-
-void microdev_outsl(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned long *port_addr;
-       const unsigned int *buf = buffer;
-
-       port_addr = (volatile unsigned long *)PORT2ADDR(port);
-
-       while (count--)
-               *port_addr = *buf++;
+       return (void __iomem *)result;
 }
index d1df2a4fb9b885913d38a90c49ff44f7bb0ace50..d8a747291e03ed82a829e20e4e779013881f1197 100644 (file)
@@ -195,27 +195,6 @@ device_initcall(microdev_devices_setup);
 static struct sh_machine_vector mv_sh4202_microdev __initmv = {
        .mv_name                = "SH4-202 MicroDev",
        .mv_nr_irqs             = 72,
-
-       .mv_inb                 = microdev_inb,
-       .mv_inw                 = microdev_inw,
-       .mv_inl                 = microdev_inl,
-       .mv_outb                = microdev_outb,
-       .mv_outw                = microdev_outw,
-       .mv_outl                = microdev_outl,
-
-       .mv_inb_p               = microdev_inb_p,
-       .mv_inw_p               = microdev_inw_p,
-       .mv_inl_p               = microdev_inl_p,
-       .mv_outb_p              = microdev_outb_p,
-       .mv_outw_p              = microdev_outw_p,
-       .mv_outl_p              = microdev_outl_p,
-
-       .mv_insb                = microdev_insb,
-       .mv_insw                = microdev_insw,
-       .mv_insl                = microdev_insl,
-       .mv_outsb               = microdev_outsb,
-       .mv_outsw               = microdev_outsw,
-       .mv_outsl               = microdev_outsl,
-
+       .mv_ioport_map          = microdev_ioport_map,
        .mv_init_irq            = init_microdev_irq,
 };
index 63e7ed699f39b3c41d8578daa8b57ce31807c689..5c9eaa0535b935c5f90bde958b0ca79724e1dcc2 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the 7206 SolutionEngine specific parts of the kernel
 #
 
-obj-y   := setup.o io.o irq.o
+obj-y   := setup.o irq.o
diff --git a/arch/sh/boards/mach-se/7206/io.c b/arch/sh/boards/mach-se/7206/io.c
deleted file mode 100644 (file)
index adadc77..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/* $Id: io.c,v 1.5 2004/02/22 23:08:43 kkojima Exp $
- *
- * linux/arch/sh/boards/se/7206/io.c
- *
- * Copyright (C) 2006 Yoshinori Sato
- *
- * I/O routine for Hitachi 7206 SolutionEngine.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <asm/io.h>
-#include <mach-se/mach/se7206.h>
-
-
-static inline void delay(void)
-{
-       __raw_readw(0x20000000);  /* P2 ROM Area */
-}
-
-/* MS7750 requires special versions of in*, out* routines, since
-   PC-like io ports are located at upper half byte of 16-bit word which
-   can be accessed only with 16-bit wide.  */
-
-static inline volatile __u16 *
-port2adr(unsigned int port)
-{
-       if (port >= 0x2000 && port < 0x2020)
-               return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       else if (port >= 0x300 && port < 0x310)
-               return (volatile __u16 *) (PA_SMSC + (port - 0x300));
-
-       return (volatile __u16 *)port;
-}
-
-unsigned char se7206_inb(unsigned long port)
-{
-       return (*port2adr(port)) & 0xff;
-}
-
-unsigned char se7206_inb_p(unsigned long port)
-{
-       unsigned long v;
-
-       v = (*port2adr(port)) & 0xff;
-       delay();
-       return v;
-}
-
-unsigned short se7206_inw(unsigned long port)
-{
-       return *port2adr(port);
-}
-
-void se7206_outb(unsigned char value, unsigned long port)
-{
-       *(port2adr(port)) = value;
-}
-
-void se7206_outb_p(unsigned char value, unsigned long port)
-{
-       *(port2adr(port)) = value;
-       delay();
-}
-
-void se7206_outw(unsigned short value, unsigned long port)
-{
-       *port2adr(port) = value;
-}
-
-void se7206_insb(unsigned long port, void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       __u8 *ap = addr;
-
-       while (count--)
-               *ap++ = *p;
-}
-
-void se7206_insw(unsigned long port, void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       __u16 *ap = addr;
-       while (count--)
-               *ap++ = *p;
-}
-
-void se7206_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       const __u8 *ap = addr;
-
-       while (count--)
-               *p = *ap++;
-}
-
-void se7206_outsw(unsigned long port, const void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       const __u16 *ap = addr;
-       while (count--)
-               *p = *ap++;
-}
index 883b21eacaa686d00efbf822911dac79e6e220d5..d961949600fd462199f3d9706e86371e815e7b1b 100644 (file)
@@ -139,11 +139,13 @@ void __init init_se7206_IRQ(void)
        make_se7206_irq(IRQ0_IRQ); /* SMC91C111 */
        make_se7206_irq(IRQ1_IRQ); /* ATA */
        make_se7206_irq(IRQ3_IRQ); /* SLOT / PCM */
-       __raw_writew(inw(INTC_ICR1) | 0x000b ,INTC_ICR1 ) ; /* ICR1 */
+
+       __raw_writew(__raw_readw(INTC_ICR1) | 0x000b, INTC_ICR); /* ICR1 */
 
        /* FPGA System register setup*/
        __raw_writew(0x0000,INTSTS0); /* Clear INTSTS0 */
        __raw_writew(0x0000,INTSTS1); /* Clear INTSTS1 */
+
        /* IRQ0=LAN, IRQ1=ATA, IRQ3=SLT,PCM */
        __raw_writew(0x0001,INTSEL);
 }
index 8f5c65d43d1d85a6e1db054cd5f065ee3aa72119..7f4871c71a01813dbd11882d9c55469d46359ce0 100644 (file)
@@ -86,20 +86,5 @@ __initcall(se7206_devices_setup);
 static struct sh_machine_vector mv_se __initmv = {
        .mv_name                = "SolutionEngine",
        .mv_nr_irqs             = 256,
-       .mv_inb                 = se7206_inb,
-       .mv_inw                 = se7206_inw,
-       .mv_outb                = se7206_outb,
-       .mv_outw                = se7206_outw,
-
-       .mv_inb_p               = se7206_inb_p,
-       .mv_inw_p               = se7206_inw,
-       .mv_outb_p              = se7206_outb_p,
-       .mv_outw_p              = se7206_outw,
-
-       .mv_insb                = se7206_insb,
-       .mv_insw                = se7206_insw,
-       .mv_outsb               = se7206_outsb,
-       .mv_outsw               = se7206_outsw,
-
        .mv_init_irq            = init_se7206_IRQ,
 };
index 8e624b06d5ea67efc746ecab0716485d9a4742bc..43ea14feef51094d032c5b7eec98b35deff925f8 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the 770x SolutionEngine specific parts of the kernel
 #
 
-obj-y   := setup.o io.o irq.o
+obj-y   := setup.o irq.o
diff --git a/arch/sh/boards/mach-se/770x/io.c b/arch/sh/boards/mach-se/770x/io.c
deleted file mode 100644 (file)
index 28833c8..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * I/O routine for Hitachi SolutionEngine.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <asm/io.h>
-#include <mach-se/mach/se.h>
-
-/* MS7750 requires special versions of in*, out* routines, since
-   PC-like io ports are located at upper half byte of 16-bit word which
-   can be accessed only with 16-bit wide.  */
-
-static inline volatile __u16 *
-port2adr(unsigned int port)
-{
-       if (port & 0xff000000)
-               return ( volatile __u16 *) port;
-       if (port >= 0x2000)
-               return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       else if (port >= 0x1000)
-               return (volatile __u16 *) (PA_83902 + (port << 1));
-       else
-               return (volatile __u16 *) (PA_SUPERIO + (port << 1));
-}
-
-static inline int
-shifted_port(unsigned long port)
-{
-       /* For IDE registers, value is not shifted */
-       if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
-               return 0;
-       else
-               return 1;
-}
-
-unsigned char se_inb(unsigned long port)
-{
-       if (shifted_port(port))
-               return (*port2adr(port) >> 8);
-       else
-               return (*port2adr(port))&0xff;
-}
-
-unsigned char se_inb_p(unsigned long port)
-{
-       unsigned long v;
-
-       if (shifted_port(port))
-               v = (*port2adr(port) >> 8);
-       else
-               v = (*port2adr(port))&0xff;
-       ctrl_delay();
-       return v;
-}
-
-unsigned short se_inw(unsigned long port)
-{
-       if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-unsigned int se_inl(unsigned long port)
-{
-       maybebadio(port);
-       return 0;
-}
-
-void se_outb(unsigned char value, unsigned long port)
-{
-       if (shifted_port(port))
-               *(port2adr(port)) = value << 8;
-       else
-               *(port2adr(port)) = value;
-}
-
-void se_outb_p(unsigned char value, unsigned long port)
-{
-       if (shifted_port(port))
-               *(port2adr(port)) = value << 8;
-       else
-               *(port2adr(port)) = value;
-       ctrl_delay();
-}
-
-void se_outw(unsigned short value, unsigned long port)
-{
-       if (port >= 0x2000)
-               *port2adr(port) = value;
-       else
-               maybebadio(port);
-}
-
-void se_outl(unsigned int value, unsigned long port)
-{
-       maybebadio(port);
-}
-
-void se_insb(unsigned long port, void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       __u8 *ap = addr;
-
-       if (shifted_port(port)) {
-               while (count--)
-                       *ap++ = *p >> 8;
-       } else {
-               while (count--)
-                       *ap++ = *p;
-       }
-}
-
-void se_insw(unsigned long port, void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       __u16 *ap = addr;
-       while (count--)
-               *ap++ = *p;
-}
-
-void se_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
-void se_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       const __u8 *ap = addr;
-
-       if (shifted_port(port)) {
-               while (count--)
-                       *p = *ap++ << 8;
-       } else {
-               while (count--)
-                       *p = *ap++;
-       }
-}
-
-void se_outsw(unsigned long port, const void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       const __u16 *ap = addr;
-
-       while (count--)
-               *p = *ap++;
-}
-
-void se_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
index 66d39d1b0901de5a9b6da4c7fb7978223b18b502..31330c65c0cec9aa1b78abb69e5bcb95c9c4cd80 100644 (file)
@@ -195,27 +195,5 @@ static struct sh_machine_vector mv_se __initmv = {
 #elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
        .mv_nr_irqs             = 104,
 #endif
-
-       .mv_inb                 = se_inb,
-       .mv_inw                 = se_inw,
-       .mv_inl                 = se_inl,
-       .mv_outb                = se_outb,
-       .mv_outw                = se_outw,
-       .mv_outl                = se_outl,
-
-       .mv_inb_p               = se_inb_p,
-       .mv_inw_p               = se_inw,
-       .mv_inl_p               = se_inl,
-       .mv_outb_p              = se_outb_p,
-       .mv_outw_p              = se_outw,
-       .mv_outl_p              = se_outl,
-
-       .mv_insb                = se_insb,
-       .mv_insw                = se_insw,
-       .mv_insl                = se_insl,
-       .mv_outsb               = se_outsb,
-       .mv_outsw               = se_outsw,
-       .mv_outsl               = se_outsl,
-
        .mv_init_irq            = init_se_IRQ,
 };
index e6f4341bfe6eaa0467e60dfb56ae08688ea5a9c0..a338fd9d503944f84b4e84b5a3a3e7cccc4a5fcb 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the 7751 SolutionEngine specific parts of the kernel
 #
 
-obj-y   := setup.o io.o irq.o
+obj-y   := setup.o irq.o
diff --git a/arch/sh/boards/mach-se/7751/io.c b/arch/sh/boards/mach-se/7751/io.c
deleted file mode 100644 (file)
index 6e75bd4..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for Hitachi 7751 SolutionEngine.
- *
- * Initial version only to support LAN access; some
- * placeholder code from io_se.c left in with the
- * expectation of later SuperIO and PCMCIA access.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <mach-se/mach/se7751.h>
-#include <asm/addrspace.h>
-
-static inline volatile u16 *port2adr(unsigned int port)
-{
-       if (port >= 0x2000)
-               return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       maybebadio((unsigned long)port);
-       return (volatile __u16*)port;
-}
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used  w/o translation for
- * compatibility.
- */
-unsigned char sh7751se_inb(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned char *)port;
-       else
-               return (*port2adr(port)) & 0xff;
-}
-
-unsigned char sh7751se_inb_p(unsigned long port)
-{
-       unsigned char v;
-
-        if (PXSEG(port))
-                v = *(volatile unsigned char *)port;
-       else
-               v = (*port2adr(port)) & 0xff;
-       ctrl_delay();
-       return v;
-}
-
-unsigned short sh7751se_inw(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned short *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-unsigned int sh7751se_inl(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned long *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-void sh7751se_outb(unsigned char value, unsigned long port)
-{
-
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-       else
-               *(port2adr(port)) = value;
-}
-
-void sh7751se_outb_p(unsigned char value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-       else
-               *(port2adr(port)) = value;
-       ctrl_delay();
-}
-
-void sh7751se_outw(unsigned short value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned short *)port = value;
-       else if (port >= 0x2000)
-               *port2adr(port) = value;
-       else
-               maybebadio(port);
-}
-
-void sh7751se_outl(unsigned int value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned long *)port = value;
-       else
-               maybebadio(port);
-}
-
-void sh7751se_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
-void sh7751se_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
index 50572512e3e84a6db630114a57415153fd4e0506..9fbc51beb1812dfafd10a91cf7b6c02c1cabfdce 100644 (file)
@@ -56,23 +56,5 @@ __initcall(se7751_devices_setup);
 static struct sh_machine_vector mv_7751se __initmv = {
        .mv_name                = "7751 SolutionEngine",
        .mv_nr_irqs             = 72,
-
-       .mv_inb                 = sh7751se_inb,
-       .mv_inw                 = sh7751se_inw,
-       .mv_inl                 = sh7751se_inl,
-       .mv_outb                = sh7751se_outb,
-       .mv_outw                = sh7751se_outw,
-       .mv_outl                = sh7751se_outl,
-
-       .mv_inb_p               = sh7751se_inb_p,
-       .mv_inw_p               = sh7751se_inw,
-       .mv_inl_p               = sh7751se_inl,
-       .mv_outb_p              = sh7751se_outb_p,
-       .mv_outw_p              = sh7751se_outw,
-       .mv_outl_p              = sh7751se_outl,
-
-       .mv_insl                = sh7751se_insl,
-       .mv_outsl               = sh7751se_outsl,
-
        .mv_init_irq            = init_7751se_IRQ,
 };
diff --git a/arch/sh/boards/mach-snapgear/Makefile b/arch/sh/boards/mach-snapgear/Makefile
deleted file mode 100644 (file)
index d2d2f4b..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the SnapGear specific parts of the kernel
-#
-
-obj-y   := setup.o io.o
diff --git a/arch/sh/boards/mach-snapgear/io.c b/arch/sh/boards/mach-snapgear/io.c
deleted file mode 100644 (file)
index 476650e..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2002  David McCullough <davidm@snapgear.com>
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for Hitachi 7751 SolutionEngine.
- *
- * Initial version only to support LAN access; some
- * placeholder code from io_se.c left in with the
- * expectation of later SuperIO and PCMCIA access.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/addrspace.h>
-
-#ifdef CONFIG_SH_SECUREEDGE5410
-unsigned short secureedge5410_ioport;
-#endif
-
-static inline volatile __u16 *port2adr(unsigned int port)
-{
-       maybebadio((unsigned long)port);
-       return (volatile __u16*)port;
-}
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used  w/o translation for
- * compatibility.
- */
-unsigned char snapgear_inb(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned char *)port;
-       else
-               return (*port2adr(port)) & 0xff;
-}
-
-unsigned char snapgear_inb_p(unsigned long port)
-{
-       unsigned char v;
-
-       if (PXSEG(port))
-               v = *(volatile unsigned char *)port;
-       else
-               v = (*port2adr(port))&0xff;
-       ctrl_delay();
-       return v;
-}
-
-unsigned short snapgear_inw(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned short *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-unsigned int snapgear_inl(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned long *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-void snapgear_outb(unsigned char value, unsigned long port)
-{
-
-       if (PXSEG(port))
-               *(volatile unsigned char *)port = value;
-       else
-               *(port2adr(port)) = value;
-}
-
-void snapgear_outb_p(unsigned char value, unsigned long port)
-{
-       if (PXSEG(port))
-               *(volatile unsigned char *)port = value;
-       else
-               *(port2adr(port)) = value;
-       ctrl_delay();
-}
-
-void snapgear_outw(unsigned short value, unsigned long port)
-{
-       if (PXSEG(port))
-               *(volatile unsigned short *)port = value;
-       else if (port >= 0x2000)
-               *port2adr(port) = value;
-       else
-               maybebadio(port);
-}
-
-void snapgear_outl(unsigned int value, unsigned long port)
-{
-       if (PXSEG(port))
-               *(volatile unsigned long *)port = value;
-       else
-               maybebadio(port);
-}
-
-void snapgear_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
-void snapgear_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
diff --git a/arch/sh/boards/mach-snapgear/setup.c b/arch/sh/boards/mach-snapgear/setup.c
deleted file mode 100644 (file)
index 331745d..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * linux/arch/sh/boards/snapgear/setup.c
- *
- * Copyright (C) 2002  David McCullough <davidm@snapgear.com>
- * Copyright (C) 2003  Paul Mundt <lethal@linux-sh.org>
- *
- * Based on files with the following comments:
- *
- *           Copyright (C) 2000  Kazumoto Kojima
- *
- *           Modified for 7751 Solution Engine by
- *           Ian da Silva and Jeremy Siegel, 2001.
- */
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <asm/machvec.h>
-#include <mach/snapgear.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <cpu/timer.h>
-
-/*
- * EraseConfig handling functions
- */
-
-static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id)
-{
-       (void)__raw_readb(0xb8000000);  /* dummy read */
-
-       printk("SnapGear: erase switch interrupt!\n");
-
-       return IRQ_HANDLED;
-}
-
-static int __init eraseconfig_init(void)
-{
-       printk("SnapGear: EraseConfig init\n");
-       /* Setup "EraseConfig" switch on external IRQ 0 */
-       if (request_irq(IRL0_IRQ, eraseconfig_interrupt, IRQF_DISABLED,
-                               "Erase Config", NULL))
-               printk("SnapGear: failed to register IRQ%d for Reset witch\n",
-                               IRL0_IRQ);
-       else
-               printk("SnapGear: registered EraseConfig switch on IRQ%d\n",
-                               IRL0_IRQ);
-       return(0);
-}
-
-module_init(eraseconfig_init);
-
-/****************************************************************************/
-/*
- * Initialize IRQ setting
- *
- * IRL0 = erase switch
- * IRL1 = eth0
- * IRL2 = eth1
- * IRL3 = crypto
- */
-
-static void __init init_snapgear_IRQ(void)
-{
-       printk("Setup SnapGear IRQ/IPR ...\n");
-       /* enable individual interrupt mode for externals */
-       plat_irq_setup_pins(IRQ_MODE_IRQ);
-}
-
-/*
- * The Machine Vector
- */
-static struct sh_machine_vector mv_snapgear __initmv = {
-       .mv_name                = "SnapGear SecureEdge5410",
-       .mv_nr_irqs             = 72,
-
-       .mv_inb                 = snapgear_inb,
-       .mv_inw                 = snapgear_inw,
-       .mv_inl                 = snapgear_inl,
-       .mv_outb                = snapgear_outb,
-       .mv_outw                = snapgear_outw,
-       .mv_outl                = snapgear_outl,
-
-       .mv_inb_p               = snapgear_inb_p,
-       .mv_inw_p               = snapgear_inw,
-       .mv_inl_p               = snapgear_inl,
-       .mv_outb_p              = snapgear_outb_p,
-       .mv_outw_p              = snapgear_outw,
-       .mv_outl_p              = snapgear_outl,
-
-       .mv_init_irq            = init_snapgear_IRQ,
-};
diff --git a/arch/sh/boards/mach-systemh/Makefile b/arch/sh/boards/mach-systemh/Makefile
deleted file mode 100644 (file)
index 2cc6a23..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# Makefile for the SystemH specific parts of the kernel
-#
-
-obj-y   := setup.o irq.o io.o
-
-# XXX: This wants to be consolidated in arch/sh/drivers/pci, and more
-# importantly, with the generic sh7751_pcic_init() code. For now, we'll
-# just abuse the hell out of kbuild, because we can..
-
-obj-$(CONFIG_PCI) += pci.o
-pci-y := ../../se/7751/pci.o
-
diff --git a/arch/sh/boards/mach-systemh/io.c b/arch/sh/boards/mach-systemh/io.c
deleted file mode 100644 (file)
index 15577ff..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/systemh/io.c
- *
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for Hitachi 7751 Systemh.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <mach/systemh7751.h>
-#include <asm/addrspace.h>
-#include <asm/io.h>
-
-#define ETHER_IOMAP(adr) (0xB3000000 + (adr)) /*map to 16bits access area
-                                                of smc lan chip*/
-static inline volatile __u16 *
-port2adr(unsigned int port)
-{
-       if (port >= 0x2000)
-               return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       maybebadio((unsigned long)port);
-       return (volatile __u16*)port;
-}
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used  w/o translation for
- * compatibility.
- */
-unsigned char sh7751systemh_inb(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned char *)port;
-       else if (port <= 0x3F1)
-               return *(volatile unsigned char *)ETHER_IOMAP(port);
-       else
-               return (*port2adr(port))&0xff;
-}
-
-unsigned char sh7751systemh_inb_p(unsigned long port)
-{
-       unsigned char v;
-
-        if (PXSEG(port))
-                v = *(volatile unsigned char *)port;
-       else if (port <= 0x3F1)
-               v = *(volatile unsigned char *)ETHER_IOMAP(port);
-       else
-               v = (*port2adr(port))&0xff;
-       ctrl_delay();
-       return v;
-}
-
-unsigned short sh7751systemh_inw(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned short *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else if (port <= 0x3F1)
-               return *(volatile unsigned int *)ETHER_IOMAP(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-unsigned int sh7751systemh_inl(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned long *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else if (port <= 0x3F1)
-               return *(volatile unsigned int *)ETHER_IOMAP(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-void sh7751systemh_outb(unsigned char value, unsigned long port)
-{
-
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-       else if (port <= 0x3F1)
-               *(volatile unsigned char *)ETHER_IOMAP(port) = value;
-       else
-               *(port2adr(port)) = value;
-}
-
-void sh7751systemh_outb_p(unsigned char value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-       else if (port <= 0x3F1)
-               *(volatile unsigned char *)ETHER_IOMAP(port) = value;
-       else
-               *(port2adr(port)) = value;
-       ctrl_delay();
-}
-
-void sh7751systemh_outw(unsigned short value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned short *)port = value;
-       else if (port >= 0x2000)
-               *port2adr(port) = value;
-       else if (port <= 0x3F1)
-               *(volatile unsigned short *)ETHER_IOMAP(port) = value;
-       else
-               maybebadio(port);
-}
-
-void sh7751systemh_outl(unsigned int value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned long *)port = value;
-       else
-               maybebadio(port);
-}
-
-void sh7751systemh_insb(unsigned long port, void *addr, unsigned long count)
-{
-       unsigned char *p = addr;
-       while (count--) *p++ = sh7751systemh_inb(port);
-}
-
-void sh7751systemh_insw(unsigned long port, void *addr, unsigned long count)
-{
-       unsigned short *p = addr;
-       while (count--) *p++ = sh7751systemh_inw(port);
-}
-
-void sh7751systemh_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
-void sh7751systemh_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       unsigned char *p = (unsigned char*)addr;
-       while (count--) sh7751systemh_outb(*p++, port);
-}
-
-void sh7751systemh_outsw(unsigned long port, const void *addr, unsigned long count)
-{
-       unsigned short *p = (unsigned short*)addr;
-       while (count--) sh7751systemh_outw(*p++, port);
-}
-
-void sh7751systemh_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
diff --git a/arch/sh/boards/mach-systemh/irq.c b/arch/sh/boards/mach-systemh/irq.c
deleted file mode 100644 (file)
index e5ee13a..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/systemh/irq.c
- *
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * Hitachi SystemH Support.
- *
- * Modified for 7751 SystemH by
- * Jonathan Short.
- */
-
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-
-#include <mach/systemh7751.h>
-#include <asm/smc37c93x.h>
-
-/* address of external interrupt mask register
- * address must be set prior to use these (maybe in init_XXX_irq())
- * XXX : is it better to use .config than specifying it in code? */
-static unsigned long *systemh_irq_mask_register = (unsigned long *)0xB3F10004;
-static unsigned long *systemh_irq_request_register = (unsigned long *)0xB3F10000;
-
-static void disable_systemh_irq(struct irq_data *data)
-{
-       unsigned long val, mask = 0x01 << 1;
-
-       /* Clear the "irq"th bit in the mask and set it in the request */
-       val = __raw_readl((unsigned long)systemh_irq_mask_register);
-       val &= ~mask;
-       __raw_writel(val, (unsigned long)systemh_irq_mask_register);
-
-       val = __raw_readl((unsigned long)systemh_irq_request_register);
-       val |= mask;
-       __raw_writel(val, (unsigned long)systemh_irq_request_register);
-}
-
-static void enable_systemh_irq(struct irq_data *data)
-{
-       unsigned long val, mask = 0x01 << 1;
-
-       /* Set "irq"th bit in the mask register */
-       val = __raw_readl((unsigned long)systemh_irq_mask_register);
-       val |= mask;
-       __raw_writel(val, (unsigned long)systemh_irq_mask_register);
-}
-
-static struct irq_chip systemh_irq_type = {
-       .name           = "SystemH Register",
-       .irq_unmask     = enable_systemh_irq,
-       .irq_mask       = disable_systemh_irq,
-};
-
-void make_systemh_irq(unsigned int irq)
-{
-       disable_irq_nosync(irq);
-       set_irq_chip_and_handler(irq, &systemh_irq_type, handle_level_irq);
-       disable_systemh_irq(irq_get_irq_data(irq));
-}
diff --git a/arch/sh/boards/mach-systemh/setup.c b/arch/sh/boards/mach-systemh/setup.c
deleted file mode 100644 (file)
index 219fd80..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/systemh/setup.c
- *
- * Copyright (C) 2000  Kazumoto Kojima
- * Copyright (C) 2003  Paul Mundt
- *
- * Hitachi SystemH Support.
- *
- * Modified for 7751 SystemH by Jonathan Short.
- *
- * Rewritten for 2.6 by Paul Mundt.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/init.h>
-#include <asm/machvec.h>
-#include <mach/systemh7751.h>
-
-extern void make_systemh_irq(unsigned int irq);
-
-/*
- * Initialize IRQ setting
- */
-static void __init sh7751systemh_init_irq(void)
-{
-       make_systemh_irq(0xb);  /* Ethernet interrupt */
-}
-
-static struct sh_machine_vector mv_7751systemh __initmv = {
-       .mv_name                = "7751 SystemH",
-       .mv_nr_irqs             = 72,
-
-       .mv_inb                 = sh7751systemh_inb,
-       .mv_inw                 = sh7751systemh_inw,
-       .mv_inl                 = sh7751systemh_inl,
-       .mv_outb                = sh7751systemh_outb,
-       .mv_outw                = sh7751systemh_outw,
-       .mv_outl                = sh7751systemh_outl,
-
-       .mv_inb_p               = sh7751systemh_inb_p,
-       .mv_inw_p               = sh7751systemh_inw,
-       .mv_inl_p               = sh7751systemh_inl,
-       .mv_outb_p              = sh7751systemh_outb_p,
-       .mv_outw_p              = sh7751systemh_outw,
-       .mv_outl_p              = sh7751systemh_outl,
-
-       .mv_insb                = sh7751systemh_insb,
-       .mv_insw                = sh7751systemh_insw,
-       .mv_insl                = sh7751systemh_insl,
-       .mv_outsb               = sh7751systemh_outsb,
-       .mv_outsw               = sh7751systemh_outsw,
-       .mv_outsl               = sh7751systemh_outsl,
-
-       .mv_init_irq            = sh7751systemh_init_irq,
-};
diff --git a/arch/sh/configs/secureedge5410_defconfig b/arch/sh/configs/secureedge5410_defconfig
new file mode 100644 (file)
index 0000000..7eae4e5
--- /dev/null
@@ -0,0 +1,63 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_SWAP is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_SLAB=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_CPU_SUBTYPE_SH7751R=y
+CONFIG_MEMORY_SIZE=0x01000000
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_SH_SECUREEDGE5410=y
+CONFIG_SH_DMA=y
+CONFIG_SH_DMA_API=y
+CONFIG_PCI=y
+CONFIG_NET=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK_RO=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+# CONFIG_MTD_CFI_I2 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_PLATRAM=y
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_8139CP=y
+CONFIG_8139TOO=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1302=y
+CONFIG_EXT2_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_TMPFS=y
+CONFIG_CRAMFS=y
+CONFIG_ROMFS_FS=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff --git a/arch/sh/configs/snapgear_defconfig b/arch/sh/configs/snapgear_defconfig
deleted file mode 100644 (file)
index 7eae4e5..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_SLAB=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_CPU_SUBTYPE_SH7751R=y
-CONFIG_MEMORY_SIZE=0x01000000
-CONFIG_FLATMEM_MANUAL=y
-CONFIG_SH_SECUREEDGE5410=y
-CONFIG_SH_DMA=y
-CONFIG_SH_DMA_API=y
-CONFIG_PCI=y
-CONFIG_NET=y
-CONFIG_INET=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK_RO=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_ADV_OPTIONS=y
-CONFIG_MTD_CFI_GEOMETRY=y
-# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
-# CONFIG_MTD_CFI_I2 is not set
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_PLATRAM=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_PCI=y
-CONFIG_8139CP=y
-CONFIG_8139TOO=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_DS1302=y
-CONFIG_EXT2_FS=y
-# CONFIG_DNOTIFY is not set
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_ROMFS_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff --git a/arch/sh/configs/systemh_defconfig b/arch/sh/configs/systemh_defconfig
deleted file mode 100644 (file)
index b58dfc5..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_CPU_SUBTYPE_SH7751R=y
-CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x00400000
-CONFIG_FLATMEM_MANUAL=y
-CONFIG_SH_7751_SYSTEMH=y
-CONFIG_PREEMPT=y
-# CONFIG_STANDALONE is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=1024
-# CONFIG_INPUT is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_VT is not set
-CONFIG_HW_RANDOM=y
-CONFIG_PROC_KCORE=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_ROMFS_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
index 446b3831c2149380265476f47674d4ad4ea72b1e..3d1ae2bfaa6fd7056701e8ddc41538d94a4a1a71 100644 (file)
 /*
  * These will never work in 32-bit, don't even bother.
  */
-#define P1SEGADDR(a)   __futile_remapping_attempt
-#define P2SEGADDR(a)   __futile_remapping_attempt
-#define P3SEGADDR(a)   __futile_remapping_attempt
-#define P4SEGADDR(a)   __futile_remapping_attempt
+#define P1SEGADDR(a)   ({ (void)(a); BUG(); NULL; })
+#define P2SEGADDR(a)   ({ (void)(a); BUG(); NULL; })
+#define P3SEGADDR(a)   ({ (void)(a); BUG(); NULL; })
+#define P4SEGADDR(a)   ({ (void)(a); BUG(); NULL; })
 #endif
 #endif /* P1SEG */
 
index a15f1058bbf439b8895f1b3d277f7e1bcf05c6aa..083ea068e819e80a389d5610bc9e19243d4ed950 100644 (file)
@@ -66,7 +66,6 @@ static inline unsigned long long neff_sign_extend(unsigned long val)
 #define PHYS_ADDR_MASK29               0x1fffffff
 #define PHYS_ADDR_MASK32               0xffffffff
 
-#ifdef CONFIG_PMB
 static inline unsigned long phys_addr_mask(void)
 {
        /* Is the MMU in 29bit mode? */
@@ -75,17 +74,6 @@ static inline unsigned long phys_addr_mask(void)
 
        return PHYS_ADDR_MASK32;
 }
-#elif defined(CONFIG_32BIT)
-static inline unsigned long phys_addr_mask(void)
-{
-       return PHYS_ADDR_MASK32;
-}
-#else
-static inline unsigned long phys_addr_mask(void)
-{
-       return PHYS_ADDR_MASK29;
-}
-#endif
 
 #define PTE_PHYS_MASK          (phys_addr_mask() & PAGE_MASK)
 #define PTE_FLAGS_MASK         (~(PTE_PHYS_MASK) << PAGE_SHIFT)
index 1f1af5afff0374537f989911d4e98f51078a9c1e..10c8b1823a181ef6abd8f07766c801f7c2c6d3f1 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/compiler.h>
 #include <linux/linkage.h>
 #include <asm/types.h>
+#include <asm/uncached.h>
 
 #define AT_VECTOR_SIZE_ARCH 5 /* entries in ARCH_DLINFO */
 
@@ -137,9 +138,6 @@ extern unsigned int instruction_size(unsigned int insn);
 #define instruction_size(insn) (4)
 #endif
 
-extern unsigned long cached_to_uncached;
-extern unsigned long uncached_size;
-
 void per_cpu_trap_init(void);
 void default_idle(void);
 void cpu_idle_wait(void);
index c941b273940581bc4221458a8cabf639829e1500..a4ad1cd9bc4d02740bb8afcb1936a932b2ed3f35 100644 (file)
@@ -145,42 +145,6 @@ do {                                                               \
                __restore_dsp(prev);                            \
 } while (0)
 
-/*
- * Jump to uncached area.
- * When handling TLB or caches, we need to do it from an uncached area.
- */
-#define jump_to_uncached()                     \
-do {                                           \
-       unsigned long __dummy;                  \
-                                               \
-       __asm__ __volatile__(                   \
-               "mova   1f, %0\n\t"             \
-               "add    %1, %0\n\t"             \
-               "jmp    @%0\n\t"                \
-               " nop\n\t"                      \
-               ".balign 4\n"                   \
-               "1:"                            \
-               : "=&z" (__dummy)               \
-               : "r" (cached_to_uncached));    \
-} while (0)
-
-/*
- * Back to cached area.
- */
-#define back_to_cached()                               \
-do {                                                   \
-       unsigned long __dummy;                          \
-       ctrl_barrier();                                 \
-       __asm__ __volatile__(                           \
-               "mov.l  1f, %0\n\t"                     \
-               "jmp    @%0\n\t"                        \
-               " nop\n\t"                              \
-               ".balign 4\n"                           \
-               "1:     .long 2f\n"                     \
-               "2:"                                    \
-               : "=&r" (__dummy));                     \
-} while (0)
-
 #ifdef CONFIG_CPU_HAS_SR_RB
 #define lookup_exception_vector()      \
 ({                                     \
index 36338646dfc81832227e78d39ccf6cdc71df4963..8593bc8d1a4e74af89ace4cb2e767b9fd0567ea6 100644 (file)
@@ -34,9 +34,6 @@ do {                                                          \
                              &next->thread);                   \
 } while (0)
 
-#define jump_to_uncached()     do { } while (0)
-#define back_to_cached()       do { } while (0)
-
 #define __icbi(addr)   __asm__ __volatile__ ( "icbi %0, 0\n\t" : : "r" (addr))
 #define __ocbp(addr)   __asm__ __volatile__ ( "ocbp %0, 0\n\t" : : "r" (addr))
 #define __ocbi(addr)   __asm__ __volatile__ ( "ocbi %0, 0\n\t" : : "r" (addr))
index e3419f96626ad49719130f120bcb71bcbdb40c42..6f8816b79cf152091b1fc08e6cd4dc5d4390bfe2 100644 (file)
@@ -4,15 +4,55 @@
 #include <linux/bug.h>
 
 #ifdef CONFIG_UNCACHED_MAPPING
+extern unsigned long cached_to_uncached;
+extern unsigned long uncached_size;
 extern unsigned long uncached_start, uncached_end;
 
 extern int virt_addr_uncached(unsigned long kaddr);
 extern void uncached_init(void);
 extern void uncached_resize(unsigned long size);
+
+/*
+ * Jump to uncached area.
+ * When handling TLB or caches, we need to do it from an uncached area.
+ */
+#define jump_to_uncached()                     \
+do {                                           \
+       unsigned long __dummy;                  \
+                                               \
+       __asm__ __volatile__(                   \
+               "mova   1f, %0\n\t"             \
+               "add    %1, %0\n\t"             \
+               "jmp    @%0\n\t"                \
+               " nop\n\t"                      \
+               ".balign 4\n"                   \
+               "1:"                            \
+               : "=&z" (__dummy)               \
+               : "r" (cached_to_uncached));    \
+} while (0)
+
+/*
+ * Back to cached area.
+ */
+#define back_to_cached()                               \
+do {                                                   \
+       unsigned long __dummy;                          \
+       ctrl_barrier();                                 \
+       __asm__ __volatile__(                           \
+               "mov.l  1f, %0\n\t"                     \
+               "jmp    @%0\n\t"                        \
+               " nop\n\t"                              \
+               ".balign 4\n"                           \
+               "1:     .long 2f\n"                     \
+               "2:"                                    \
+               : "=&r" (__dummy));                     \
+} while (0)
 #else
 #define virt_addr_uncached(kaddr)      (0)
 #define uncached_init()                        do { } while (0)
 #define uncached_resize(size)          BUG()
+#define jump_to_uncached()             do { } while (0)
+#define back_to_cached()               do { } while (0)
 #endif
 
 #endif /* __ASM_SH_UNCACHED_H */
diff --git a/arch/sh/include/mach-common/mach/edosk7705.h b/arch/sh/include/mach-common/mach/edosk7705.h
deleted file mode 100644 (file)
index efc43b3..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __ASM_SH_EDOSK7705_H
-#define __ASM_SH_EDOSK7705_H
-
-#define __IO_PREFIX sh_edosk7705
-#include <asm/io_generic.h>
-
-#endif /* __ASM_SH_EDOSK7705_H */
index 1aed15856e11ff5bae72b2522f94f816084e0dee..dcb05fa8c164d9c9044df5ce85665953328f7e21 100644 (file)
@@ -68,13 +68,4 @@ extern void microdev_print_fpga_intc_status(void);
 #define __IO_PREFIX microdev
 #include <asm/io_generic.h>
 
-#if defined(CONFIG_PCI)
-unsigned char  microdev_pci_inb(unsigned long port);
-unsigned short microdev_pci_inw(unsigned long port);
-unsigned long  microdev_pci_inl(unsigned long port);
-void           microdev_pci_outb(unsigned char  data, unsigned long port);
-void           microdev_pci_outw(unsigned short data, unsigned long port);
-void           microdev_pci_outl(unsigned long  data, unsigned long port);
-#endif
-
 #endif /* __ASM_SH_MICRODEV_H */
diff --git a/arch/sh/include/mach-common/mach/secureedge5410.h b/arch/sh/include/mach-common/mach/secureedge5410.h
new file mode 100644 (file)
index 0000000..3653b9a
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * include/asm-sh/snapgear.h
+ *
+ * Modified version of io_se.h for the snapgear-specific functions.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * IO functions for a SnapGear
+ */
+
+#ifndef _ASM_SH_IO_SNAPGEAR_H
+#define _ASM_SH_IO_SNAPGEAR_H
+
+#define __IO_PREFIX    snapgear
+#include <asm/io_generic.h>
+
+/*
+ * We need to remember what was written to the ioport as some bits
+ * are shared with other functions and you cannot read back what was
+ * written :-|
+ *
+ * Bit        Read                   Write
+ * -----------------------------------------------
+ * D0         DCD on ttySC1          power
+ * D1         Reset Switch           heatbeat
+ * D2         ttySC0 CTS (7100)      LAN
+ * D3         -                      WAN
+ * D4         ttySC0 DCD (7100)      CONSOLE
+ * D5         -                      ONLINE
+ * D6         -                      VPN
+ * D7         -                      DTR on ttySC1
+ * D8         -                      ttySC0 RTS (7100)
+ * D9         -                      ttySC0 DTR (7100)
+ * D10        -                      RTC SCLK
+ * D11        RTC DATA               RTC DATA
+ * D12        -                      RTS RESET
+ */
+
+#define SECUREEDGE_IOPORT_ADDR ((volatile short *) 0xb0000000)
+extern unsigned short secureedge5410_ioport;
+
+#define SECUREEDGE_WRITE_IOPORT(val, mask) (*SECUREEDGE_IOPORT_ADDR = \
+        (secureedge5410_ioport = \
+                       ((secureedge5410_ioport & ~(mask)) | ((val) & (mask)))))
+#define SECUREEDGE_READ_IOPORT() \
+        ((*SECUREEDGE_IOPORT_ADDR&0x0817) | (secureedge5410_ioport&~0x0817))
+
+#endif /* _ASM_SH_IO_SNAPGEAR_H */
diff --git a/arch/sh/include/mach-common/mach/snapgear.h b/arch/sh/include/mach-common/mach/snapgear.h
deleted file mode 100644 (file)
index 042d95f..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * include/asm-sh/snapgear.h
- *
- * Modified version of io_se.h for the snapgear-specific functions.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * IO functions for a SnapGear
- */
-
-#ifndef _ASM_SH_IO_SNAPGEAR_H
-#define _ASM_SH_IO_SNAPGEAR_H
-
-#if defined(CONFIG_CPU_SH4)
-/*
- * The external interrupt lines, these take up ints 0 - 15 inclusive
- * depending on the priority for the interrupt.  In fact the priority
- * is the interrupt :-)
- */
-
-#define IRL0_IRQ       2
-#define IRL0_PRIORITY  13
-
-#define IRL1_IRQ       5
-#define IRL1_PRIORITY  10
-
-#define IRL2_IRQ       8
-#define IRL2_PRIORITY  7
-
-#define IRL3_IRQ       11
-#define IRL3_PRIORITY  4
-#endif
-
-#define __IO_PREFIX    snapgear
-#include <asm/io_generic.h>
-
-#ifdef CONFIG_SH_SECUREEDGE5410
-/*
- * We need to remember what was written to the ioport as some bits
- * are shared with other functions and you cannot read back what was
- * written :-|
- *
- * Bit        Read                   Write
- * -----------------------------------------------
- * D0         DCD on ttySC1          power
- * D1         Reset Switch           heatbeat
- * D2         ttySC0 CTS (7100)      LAN
- * D3         -                      WAN
- * D4         ttySC0 DCD (7100)      CONSOLE
- * D5         -                      ONLINE
- * D6         -                      VPN
- * D7         -                      DTR on ttySC1
- * D8         -                      ttySC0 RTS (7100)
- * D9         -                      ttySC0 DTR (7100)
- * D10        -                      RTC SCLK
- * D11        RTC DATA               RTC DATA
- * D12        -                      RTS RESET
- */
-
-#define SECUREEDGE_IOPORT_ADDR ((volatile short *) 0xb0000000)
-extern unsigned short secureedge5410_ioport;
-
-#define SECUREEDGE_WRITE_IOPORT(val, mask) (*SECUREEDGE_IOPORT_ADDR = \
-        (secureedge5410_ioport = \
-                       ((secureedge5410_ioport & ~(mask)) | ((val) & (mask)))))
-#define SECUREEDGE_READ_IOPORT() \
-        ((*SECUREEDGE_IOPORT_ADDR&0x0817) | (secureedge5410_ioport&~0x0817))
-#endif
-
-#endif /* _ASM_SH_IO_SNAPGEAR_H */
diff --git a/arch/sh/include/mach-common/mach/systemh7751.h b/arch/sh/include/mach-common/mach/systemh7751.h
deleted file mode 100644 (file)
index 4161122..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef __ASM_SH_SYSTEMH_7751SYSTEMH_H
-#define __ASM_SH_SYSTEMH_7751SYSTEMH_H
-
-/*
- * linux/include/asm-sh/systemh/7751systemh.h
- *
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * Hitachi SystemH support
-
- * Modified for 7751 SystemH by
- * Jonathan Short, 2002.
- */
-
-/* Box specific addresses.  */
-
-#define PA_ROM         0x00000000      /* EPROM */
-#define PA_ROM_SIZE    0x00400000      /* EPROM size 4M byte */
-#define PA_FROM                0x01000000      /* EPROM */
-#define PA_FROM_SIZE   0x00400000      /* EPROM size 4M byte */
-#define PA_EXT1                0x04000000
-#define PA_EXT1_SIZE   0x04000000
-#define PA_EXT2                0x08000000
-#define PA_EXT2_SIZE   0x04000000
-#define PA_SDRAM       0x0c000000
-#define PA_SDRAM_SIZE  0x04000000
-
-#define PA_EXT4                0x12000000
-#define PA_EXT4_SIZE   0x02000000
-#define PA_EXT5                0x14000000
-#define PA_EXT5_SIZE   0x04000000
-#define PA_PCIC                0x18000000      /* MR-SHPC-01 PCMCIA */
-
-#define PA_DIPSW0      0xb9000000      /* Dip switch 5,6 */
-#define PA_DIPSW1      0xb9000002      /* Dip switch 7,8 */
-#define PA_LED         0xba000000      /* LED */
-#define        PA_BCR          0xbb000000      /* FPGA on the MS7751SE01 */
-
-#define PA_MRSHPC      0xb83fffe0      /* MR-SHPC-01 PCMCIA controller */
-#define PA_MRSHPC_MW1  0xb8400000      /* MR-SHPC-01 memory window base */
-#define PA_MRSHPC_MW2  0xb8500000      /* MR-SHPC-01 attribute window base */
-#define PA_MRSHPC_IO   0xb8600000      /* MR-SHPC-01 I/O window base */
-#define MRSHPC_MODE     (PA_MRSHPC + 4)
-#define MRSHPC_OPTION   (PA_MRSHPC + 6)
-#define MRSHPC_CSR      (PA_MRSHPC + 8)
-#define MRSHPC_ISR      (PA_MRSHPC + 10)
-#define MRSHPC_ICR      (PA_MRSHPC + 12)
-#define MRSHPC_CPWCR    (PA_MRSHPC + 14)
-#define MRSHPC_MW0CR1   (PA_MRSHPC + 16)
-#define MRSHPC_MW1CR1   (PA_MRSHPC + 18)
-#define MRSHPC_IOWCR1   (PA_MRSHPC + 20)
-#define MRSHPC_MW0CR2   (PA_MRSHPC + 22)
-#define MRSHPC_MW1CR2   (PA_MRSHPC + 24)
-#define MRSHPC_IOWCR2   (PA_MRSHPC + 26)
-#define MRSHPC_CDCR     (PA_MRSHPC + 28)
-#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
-
-#define BCR_ILCRA      (PA_BCR + 0)
-#define BCR_ILCRB      (PA_BCR + 2)
-#define BCR_ILCRC      (PA_BCR + 4)
-#define BCR_ILCRD      (PA_BCR + 6)
-#define BCR_ILCRE      (PA_BCR + 8)
-#define BCR_ILCRF      (PA_BCR + 10)
-#define BCR_ILCRG      (PA_BCR + 12)
-
-#define IRQ_79C973     13
-
-#define __IO_PREFIX    sh7751systemh
-#include <asm/io_generic.h>
-
-#endif  /* __ASM_SH_SYSTEMH_7751SYSTEMH_H */
index 2d9700c6b53a07426bdc6253e55a62effed962c0..0fe2e9329cb25f699acd433dd4f2d9b4b945f00b 100644 (file)
@@ -48,7 +48,7 @@ static struct clk r_clk = {
  * Default rate for the root input clock, reset this with clk_set_rate()
  * from the platform code.
  */
-struct clk extal_clk = {
+static struct clk extal_clk = {
        .rate           = 33333333,
 };
 
@@ -111,7 +111,7 @@ static struct clk div3_clk = {
        .parent         = &pll_clk,
 };
 
-struct clk *main_clks[] = {
+static struct clk *main_clks[] = {
        &r_clk,
        &extal_clk,
        &fll_clk,
@@ -156,7 +156,7 @@ struct clk div4_clks[DIV4_NR] = {
 
 enum { DIV6_V, DIV6_FA, DIV6_FB, DIV6_I, DIV6_S, DIV6_NR };
 
-struct clk div6_clks[DIV6_NR] = {
+static struct clk div6_clks[DIV6_NR] = {
        [DIV6_V] = SH_CLK_DIV6(&div3_clk, VCLKCR, 0),
        [DIV6_FA] = SH_CLK_DIV6(&div3_clk, FCLKACR, 0),
        [DIV6_FB] = SH_CLK_DIV6(&div3_clk, FCLKBCR, 0),
index 09370392aff15d791d612ac57bcdf0c6031d8443..c3e61b36649380f5db818c5f6edb05bfc897de1c 100644 (file)
@@ -79,7 +79,7 @@ config 29BIT
 
 config 32BIT
        bool
-       default y if CPU_SH5
+       default y if CPU_SH5 || !MMU
 
 config PMB
        bool "Support 32-bit physical addressing through PMB"
index 0387932869904a042472cca19b65141b5b8bdc9f..40733a9524021d42d42ddc5a8d7e08ef77a1c155 100644 (file)
@@ -79,21 +79,20 @@ void dma_generic_free_coherent(struct device *dev, size_t size,
 void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
                    enum dma_data_direction direction)
 {
-#if defined(CONFIG_CPU_SH5) || defined(CONFIG_PMB)
-       void *p1addr = vaddr;
-#else
-       void *p1addr = (void*) P1SEGADDR((unsigned long)vaddr);
-#endif
+       void *addr;
+
+       addr = __in_29bit_mode() ?
+              (void *)P1SEGADDR((unsigned long)vaddr) : vaddr;
 
        switch (direction) {
        case DMA_FROM_DEVICE:           /* invalidate only */
-               __flush_invalidate_region(p1addr, size);
+               __flush_invalidate_region(addr, size);
                break;
        case DMA_TO_DEVICE:             /* writeback only */
-               __flush_wback_region(p1addr, size);
+               __flush_wback_region(addr, size);
                break;
        case DMA_BIDIRECTIONAL:         /* writeback and invalidate */
-               __flush_purge_region(p1addr, size);
+               __flush_purge_region(addr, size);
                break;
        default:
                BUG();
index 8a4eca551fc0a08542085faddeac7af373ad091b..a7767da815e91453c5b5526a05f4c72405e4afba 100644 (file)
@@ -28,7 +28,7 @@ EXPORT_SYMBOL(virt_addr_uncached);
 
 void __init uncached_init(void)
 {
-#ifdef CONFIG_29BIT
+#if defined(CONFIG_29BIT) || !defined(CONFIG_MMU)
        uncached_start = P2SEG;
 #else
        uncached_start = memory_end;
index 9f56eb978024ef2b6e93497a6580d00dbc7f62eb..0e68465e7b50920ffcaa8a832402fdfc3670226c 100644 (file)
@@ -26,7 +26,6 @@ HD64461                       HD64461
 7724SE                 SH_7724_SOLUTION_ENGINE
 7751SE                 SH_7751_SOLUTION_ENGINE
 7780SE                 SH_7780_SOLUTION_ENGINE
-7751SYSTEMH            SH_7751_SYSTEMH
 HP6XX                  SH_HP6XX
 DREAMCAST              SH_DREAMCAST
 SNAPGEAR               SH_SECUREEDGE5410
index e0f7ee186721cf554dc142efdfc58350eaf6a7df..b2a6c5de79abf00ddad0354fca8b694937282131 100644 (file)
@@ -23,7 +23,6 @@
 
 #include <linux/interrupt.h>
 #include <linux/threads.h>
-#include <asm/kmap_types.h>
 #include <asm/tlbflush.h>
 #include <asm/homecache.h>
 
index 1480106d1c05c2572177058611ee655db569c41c..3d0f202462609e1401b4737b905cb324332d8b4c 100644 (file)
 #define _ASM_TILE_KMAP_TYPES_H
 
 /*
- * In TILE Linux each set of four of these uses another 16MB chunk of
- * address space, given 64 tiles and 64KB pages, so we only enable
- * ones that are required by the kernel configuration.
+ * In 32-bit TILE Linux we have to balance the desire to have a lot of
+ * nested atomic mappings with the fact that large page sizes and many
+ * processors chew up address space quickly.  In a typical
+ * 64-processor, 64KB-page layout build, making KM_TYPE_NR one larger
+ * adds 4MB of required address-space.  For now we leave KM_TYPE_NR
+ * set to depth 8.
  */
 enum km_type {
+       KM_TYPE_NR = 8
+};
+
+/*
+ * We provide dummy definitions of all the stray values that used to be
+ * required for kmap_atomic() and no longer are.
+ */
+enum {
        KM_BOUNCE_READ,
        KM_SKB_SUNRPC_DATA,
        KM_SKB_DATA_SOFTIRQ,
        KM_USER0,
        KM_USER1,
        KM_BIO_SRC_IRQ,
+       KM_BIO_DST_IRQ,
+       KM_PTE0,
+       KM_PTE1,
        KM_IRQ0,
        KM_IRQ1,
        KM_SOFTIRQ0,
        KM_SOFTIRQ1,
-       KM_MEMCPY0,
-       KM_MEMCPY1,
-#if defined(CONFIG_HIGHPTE)
-       KM_PTE0,
-       KM_PTE1,
-#endif
-       KM_TYPE_NR
+       KM_SYNC_ICACHE,
+       KM_SYNC_DCACHE,
+       KM_UML_USERCOPY,
+       KM_IRQ_PTE,
+       KM_NMI,
+       KM_NMI_PTE,
+       KM_KDB
 };
 
 #endif /* _ASM_TILE_KMAP_TYPES_H */
index dc4ccdd855bca293070ea8bff94a699821d5e01b..a6604e9485da2a188265d618eaaa8a75ec8a4828 100644 (file)
@@ -344,10 +344,8 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
 #if defined(CONFIG_HIGHPTE)
-extern pte_t *_pte_offset_map(pmd_t *, unsigned long address, enum km_type);
-#define pte_offset_map(dir, address) \
-       _pte_offset_map(dir, address, KM_PTE0)
-#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
+extern pte_t *pte_offset_map(pmd_t *, unsigned long address);
+#define pte_unmap(pte) kunmap_atomic(pte)
 #else
 #define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
 #define pte_unmap(pte) do { } while (0)
index 3dc90fa92c704d8fb07d66b034daadd44ee6376b..b16e5db8f0e7225f9e8789a747f9295d341d947d 100644 (file)
@@ -1 +1,4 @@
+#ifdef CONFIG_COMPAT
+#define __ARCH_WANT_STAT64     /* Used for compat_sys_stat64() etc. */
+#endif
 #include <asm-generic/stat.h>
index f2e3ff485333224f022344fad78f7c96b19d5243..b35c2db71199ae3d70fc2b1e29687dc350514a77 100644 (file)
@@ -41,6 +41,7 @@ __SYSCALL(__NR_cmpxchg_badaddr, sys_cmpxchg_badaddr)
 #ifdef CONFIG_COMPAT
 #define __ARCH_WANT_SYS_LLSEEK
 #endif
+#define __ARCH_WANT_SYS_NEWFSTATAT
 #endif
 
 #endif /* _ASM_TILE_UNISTD_H */
index 77739cdd9462dacf2a9188a0a0418c014e6379f9..67617a05e602380a7d1fba86dadba25db17a13ef 100644 (file)
@@ -148,11 +148,11 @@ long tile_compat_sys_msgrcv(int msqid,
 #define compat_sys_readahead sys32_readahead
 #define compat_sys_sync_file_range compat_sys_sync_file_range2
 
-/* The native 64-bit "struct stat" matches the 32-bit "struct stat64". */
-#define compat_sys_stat64 sys_newstat
-#define compat_sys_lstat64 sys_newlstat
-#define compat_sys_fstat64 sys_newfstat
-#define compat_sys_fstatat64 sys_newfstatat
+/* We leverage the "struct stat64" type for 32-bit time_t/nsec. */
+#define compat_sys_stat64 sys_stat64
+#define compat_sys_lstat64 sys_lstat64
+#define compat_sys_fstat64 sys_fstat64
+#define compat_sys_fstatat64 sys_fstatat64
 
 /* The native sys_ptrace dynamically handles compat binaries. */
 #define compat_sys_ptrace sys_ptrace
index 2c54fd43a8a0132533927ed5b5e373940f10ce18..493a0e66d916c618f867034db5647f72acd61999 100644 (file)
@@ -54,7 +54,7 @@ void early_printk(const char *fmt, ...)
 void early_panic(const char *fmt, ...)
 {
        va_list ap;
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        va_start(ap, fmt);
        early_printk("Kernel panic - not syncing: ");
        early_vprintk(fmt, ap);
index 1e54a7843410e57d021dbac9921acf4f39e2f481..e910530436e64a4079ba65e22bdca13e6ad01bfa 100644 (file)
@@ -151,12 +151,12 @@ enum direction_protect {
 
 static void enable_firewall_interrupts(void)
 {
-       raw_local_irq_unmask_now(INT_UDN_FIREWALL);
+       arch_local_irq_unmask_now(INT_UDN_FIREWALL);
 }
 
 static void disable_firewall_interrupts(void)
 {
-       raw_local_irq_mask_now(INT_UDN_FIREWALL);
+       arch_local_irq_mask_now(INT_UDN_FIREWALL);
 }
 
 /* Set up hardwall on this cpu based on the passed hardwall_info. */
@@ -768,13 +768,13 @@ static int hardwall_release(struct inode *inode, struct file *file)
 }
 
 static const struct file_operations dev_hardwall_fops = {
+       .open           = nonseekable_open,
        .unlocked_ioctl = hardwall_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = hardwall_compat_ioctl,
 #endif
        .flush          = hardwall_flush,
        .release        = hardwall_release,
-       .llseek         = noop_llseek,
 };
 
 static struct cdev hardwall_dev;
index e63917687e998907824a62b1783ffef599418818..128805ef8f2c83c1a8b61cf03c5711e5fbb97ff1 100644 (file)
@@ -26,7 +26,7 @@
 #define IS_HW_CLEARED 1
 
 /*
- * The set of interrupts we enable for raw_local_irq_enable().
+ * The set of interrupts we enable for arch_local_irq_enable().
  * This is initialized to have just a single interrupt that the kernel
  * doesn't actually use as a sentinel.  During kernel init,
  * interrupts are added as the kernel gets prepared to support them.
@@ -225,7 +225,7 @@ void __cpuinit setup_irq_regs(void)
        /* Enable interrupt delivery. */
        unmask_irqs(~0UL);
 #if CHIP_HAS_IPI()
-       raw_local_irq_unmask(INT_IPI_K);
+       arch_local_irq_unmask(INT_IPI_K);
 #endif
 }
 
index ba7a265d61796a09168b6c35ed74af23f9fdb256..0d8b9e933487c2847824efc1637364cba8ec84d8 100644 (file)
@@ -182,13 +182,13 @@ static void kexec_find_and_set_command_line(struct kimage *image)
 
                if ((entry & IND_SOURCE)) {
                        void *va =
-                               kmap_atomic_pfn(entry >> PAGE_SHIFT, KM_USER0);
+                               kmap_atomic_pfn(entry >> PAGE_SHIFT);
                        r = kexec_bn2cl(va);
                        if (r) {
                                command_line = r;
                                break;
                        }
-                       kunmap_atomic(va, KM_USER0);
+                       kunmap_atomic(va);
                }
        }
 
@@ -198,7 +198,7 @@ static void kexec_find_and_set_command_line(struct kimage *image)
 
                hverr = hv_set_command_line(
                        (HV_VirtAddr) command_line, strlen(command_line));
-               kunmap_atomic(command_line, KM_USER0);
+               kunmap_atomic(command_line);
        } else {
                pr_info("%s: no command line found; making empty\n",
                       __func__);
index 997e3933f72679718583dae5a82c72c4d2f9fbdb..0858ee6b520f6acf4c23b3a27c8491267919b943 100644 (file)
@@ -34,7 +34,7 @@ void __cpuinit init_messaging(void)
                panic("hv_register_message_state: error %d", rc);
 
        /* Make sure downcall interrupts will be enabled. */
-       raw_local_irq_unmask(INT_INTCTRL_K);
+       arch_local_irq_unmask(INT_INTCTRL_K);
 }
 
 void hv_message_intr(struct pt_regs *regs, int intnum)
index 9cd29884c09f2bfec1cddbacb67579bbd1e821c6..e92e40527d6dcb9855625cafa13a83f08f56df9c 100644 (file)
@@ -50,10 +50,10 @@ long arch_ptrace(struct task_struct *child, long request,
 {
        unsigned long __user *datap = (long __user __force *)data;
        unsigned long tmp;
-       int i;
        long ret = -EIO;
-       unsigned long *childregs;
        char *childreg;
+       struct pt_regs copyregs;
+       int ex1_offset;
 
        switch (request) {
 
@@ -80,6 +80,16 @@ long arch_ptrace(struct task_struct *child, long request,
                if (addr >= PTREGS_SIZE)
                        break;
                childreg = (char *)task_pt_regs(child) + addr;
+
+               /* Guard against overwrites of the privilege level. */
+               ex1_offset = PTREGS_OFFSET_EX1;
+#if defined(CONFIG_COMPAT) && defined(__BIG_ENDIAN)
+               if (is_compat_task())   /* point at low word */
+                       ex1_offset += sizeof(compat_long_t);
+#endif
+               if (addr == ex1_offset)
+                       data = PL_ICS_EX1(USER_PL, EX1_ICS(data));
+
 #ifdef CONFIG_COMPAT
                if (is_compat_task()) {
                        if (addr & (sizeof(compat_long_t)-1))
@@ -96,26 +106,19 @@ long arch_ptrace(struct task_struct *child, long request,
                break;
 
        case PTRACE_GETREGS:  /* Get all registers from the child. */
-               if (!access_ok(VERIFY_WRITE, datap, PTREGS_SIZE))
-                       break;
-               childregs = (long *)task_pt_regs(child);
-               for (i = 0; i < sizeof(struct pt_regs)/sizeof(unsigned long);
-                               ++i) {
-                       ret = __put_user(childregs[i], &datap[i]);
-                       if (ret != 0)
-                               break;
+               if (copy_to_user(datap, task_pt_regs(child),
+                                sizeof(struct pt_regs)) == 0) {
+                       ret = 0;
                }
                break;
 
        case PTRACE_SETREGS:  /* Set all registers in the child. */
-               if (!access_ok(VERIFY_READ, datap, PTREGS_SIZE))
-                       break;
-               childregs = (long *)task_pt_regs(child);
-               for (i = 0; i < sizeof(struct pt_regs)/sizeof(unsigned long);
-                               ++i) {
-                       ret = __get_user(childregs[i], &datap[i]);
-                       if (ret != 0)
-                               break;
+               if (copy_from_user(&copyregs, datap,
+                                  sizeof(struct pt_regs)) == 0) {
+                       copyregs.ex1 =
+                               PL_ICS_EX1(USER_PL, EX1_ICS(copyregs.ex1));
+                       *task_pt_regs(child) = copyregs;
+                       ret = 0;
                }
                break;
 
index acd86d20beba7ab75aed0f484c3b980a836af282..baa3d905fee21c9fc2ef403449f7e4d671ad7e1e 100644 (file)
@@ -27,7 +27,7 @@
 void machine_halt(void)
 {
        warn_early_printk();
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        smp_send_stop();
        hv_halt();
 }
@@ -35,14 +35,14 @@ void machine_halt(void)
 void machine_power_off(void)
 {
        warn_early_printk();
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        smp_send_stop();
        hv_power_off();
 }
 
 void machine_restart(char *cmd)
 {
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        smp_send_stop();
        hv_restart((HV_VirtAddr) "vmlinux", (HV_VirtAddr) cmd);
 }
index ae51cad12da0d6b445666d1796925816b8e7e285..fb0b3cbeae149081a5b3011f0230fbd48f4d56dd 100644 (file)
@@ -868,14 +868,14 @@ void __cpuinit setup_cpu(int boot)
 
        /* Allow asynchronous TLB interrupts. */
 #if CHIP_HAS_TILE_DMA()
-       raw_local_irq_unmask(INT_DMATLB_MISS);
-       raw_local_irq_unmask(INT_DMATLB_ACCESS);
+       arch_local_irq_unmask(INT_DMATLB_MISS);
+       arch_local_irq_unmask(INT_DMATLB_ACCESS);
 #endif
 #if CHIP_HAS_SN_PROC()
-       raw_local_irq_unmask(INT_SNITLB_MISS);
+       arch_local_irq_unmask(INT_SNITLB_MISS);
 #endif
 #ifdef __tilegx__
-       raw_local_irq_unmask(INT_SINGLE_STEP_K);
+       arch_local_irq_unmask(INT_SINGLE_STEP_K);
 #endif
 
        /*
index fb28e85ae3aea3698c7d2cd5da564bb0a5f7fb0d..687719d4abd1eba56fbd591852c8fab51950bc52 100644 (file)
@@ -71,6 +71,9 @@ int restore_sigcontext(struct pt_regs *regs,
        for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i)
                err |= __get_user(regs->regs[i], &sc->gregs[i]);
 
+       /* Ensure that the PL is always set to USER_PL. */
+       regs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(regs->ex1));
+
        regs->faultnum = INT_SWINT_1_SIGRETURN;
 
        err |= __get_user(*pr0, &sc->gregs[0]);
@@ -330,7 +333,7 @@ void do_signal(struct pt_regs *regs)
                        current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
                }
 
-               return;
+               goto done;
        }
 
        /* Did we come from a system call? */
@@ -358,4 +361,8 @@ void do_signal(struct pt_regs *regs)
                current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
                sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
        }
+
+done:
+       /* Avoid double syscall restart if there are nested signals. */
+       regs->faultnum = INT_SWINT_1_SIGRETURN;
 }
index 75255d90aff309669b110dff32f2254ede9daa27..9575b37a8b75318d57cd061172d7cd09d0cf8049 100644 (file)
@@ -115,7 +115,7 @@ static void smp_start_cpu_interrupt(void)
 static void smp_stop_cpu_interrupt(void)
 {
        set_cpu_online(smp_processor_id(), 0);
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        for (;;)
                asm("nap");
 }
index 6bed820e1421ae628c9ad162de3e50eb1f2884bf..f2e156e44692505e620c7e6c1a35e1ca948c3855 100644 (file)
@@ -132,7 +132,7 @@ static int tile_timer_set_next_event(unsigned long ticks,
 {
        BUG_ON(ticks > MAX_TICK);
        __insn_mtspr(SPR_TILE_TIMER_CONTROL, ticks);
-       raw_local_irq_unmask_now(INT_TILE_TIMER);
+       arch_local_irq_unmask_now(INT_TILE_TIMER);
        return 0;
 }
 
@@ -143,7 +143,7 @@ static int tile_timer_set_next_event(unsigned long ticks,
 static void tile_timer_set_mode(enum clock_event_mode mode,
                                struct clock_event_device *evt)
 {
-       raw_local_irq_mask_now(INT_TILE_TIMER);
+       arch_local_irq_mask_now(INT_TILE_TIMER);
 }
 
 /*
@@ -172,7 +172,7 @@ void __cpuinit setup_tile_timer(void)
        evt->cpumask = cpumask_of(smp_processor_id());
 
        /* Start out with timer not firing. */
-       raw_local_irq_mask_now(INT_TILE_TIMER);
+       arch_local_irq_mask_now(INT_TILE_TIMER);
 
        /* Register tile timer. */
        clockevents_register_device(evt);
@@ -188,7 +188,7 @@ void do_timer_interrupt(struct pt_regs *regs, int fault_num)
         * Mask the timer interrupt here, since we are a oneshot timer
         * and there are now by definition no events pending.
         */
-       raw_local_irq_mask(INT_TILE_TIMER);
+       arch_local_irq_mask(INT_TILE_TIMER);
 
        /* Track time spent here in an interrupt context */
        irq_enter();
index dfedea7b266b5d58e6cd445fa8ed0f8ae8fcaea8..f7d4a6ad61e811356ac6bec2b9f235c94f4355c6 100644 (file)
@@ -54,7 +54,7 @@ typedef unsigned long (*memcpy_t)(void *, const void *, unsigned long);
  * we must run with interrupts disabled to avoid the risk of some
  * other code seeing the incoherent data in our cache.  (Recall that
  * our cache is indexed by PA, so even if the other code doesn't use
- * our KM_MEMCPY virtual addresses, they'll still hit in cache using
+ * our kmap_atomic virtual addresses, they'll still hit in cache using
  * the normal VAs that aren't supposed to hit in cache.)
  */
 static void memcpy_multicache(void *dest, const void *source,
@@ -64,6 +64,7 @@ static void memcpy_multicache(void *dest, const void *source,
        unsigned long flags, newsrc, newdst;
        pmd_t *pmdp;
        pte_t *ptep;
+       int type0, type1;
        int cpu = get_cpu();
 
        /*
@@ -77,7 +78,8 @@ static void memcpy_multicache(void *dest, const void *source,
        sim_allow_multiple_caching(1);
 
        /* Set up the new dest mapping */
-       idx = FIX_KMAP_BEGIN + (KM_TYPE_NR * cpu) + KM_MEMCPY0;
+       type0 = kmap_atomic_idx_push();
+       idx = FIX_KMAP_BEGIN + (KM_TYPE_NR * cpu) + type0;
        newdst = __fix_to_virt(idx) + ((unsigned long)dest & (PAGE_SIZE-1));
        pmdp = pmd_offset(pud_offset(pgd_offset_k(newdst), newdst), newdst);
        ptep = pte_offset_kernel(pmdp, newdst);
@@ -87,7 +89,8 @@ static void memcpy_multicache(void *dest, const void *source,
        }
 
        /* Set up the new source mapping */
-       idx += (KM_MEMCPY0 - KM_MEMCPY1);
+       type1 = kmap_atomic_idx_push();
+       idx += (type0 - type1);
        src_pte = hv_pte_set_nc(src_pte);
        src_pte = hv_pte_clear_writable(src_pte);  /* be paranoid */
        newsrc = __fix_to_virt(idx) + ((unsigned long)source & (PAGE_SIZE-1));
@@ -119,6 +122,8 @@ static void memcpy_multicache(void *dest, const void *source,
         * We're done: notify the simulator that all is back to normal,
         * and re-enable interrupts and pre-emption.
         */
+       kmap_atomic_idx_pop();
+       kmap_atomic_idx_pop();
        sim_allow_multiple_caching(0);
        local_irq_restore(flags);
        put_cpu();
index abb57331cf6e1b25fdeccfd295e25ea7464ebbf5..31dbbd9afe47d5cb32590b96e1d7065e2ff5bf24 100644 (file)
@@ -227,7 +227,7 @@ EXPORT_SYMBOL(kmap_atomic_prot);
 void *__kmap_atomic(struct page *page)
 {
        /* PAGE_NONE is a magic value that tells us to check immutability. */
-       return kmap_atomic_prot(page, type, PAGE_NONE);
+       return kmap_atomic_prot(page, PAGE_NONE);
 }
 EXPORT_SYMBOL(__kmap_atomic);
 
index 78e1982cb6c9dc0385e258b81bfc233f23baaaac..0b9ce69b0ee5e755ea6186e1093269507cae156d 100644 (file)
@@ -988,8 +988,12 @@ static long __write_once initfree = 1;
 /* Select whether to free (1) or mark unusable (0) the __init pages. */
 static int __init set_initfree(char *str)
 {
-       strict_strtol(str, 0, &initfree);
-       pr_info("initfree: %s free init pages\n", initfree ? "will" : "won't");
+       long val;
+       if (strict_strtol(str, 0, &val)) {
+               initfree = val;
+               pr_info("initfree: %s free init pages\n",
+                       initfree ? "will" : "won't");
+       }
        return 1;
 }
 __setup("initfree=", set_initfree);
index 335c24621c418b1a7bffdacc2723bbcee665c8e2..1f5430c53d0db4cf62c992c656de7e1b2e9769e6 100644 (file)
@@ -134,9 +134,9 @@ void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
 }
 
 #if defined(CONFIG_HIGHPTE)
-pte_t *_pte_offset_map(pmd_t *dir, unsigned long address, enum km_type type)
+pte_t *_pte_offset_map(pmd_t *dir, unsigned long address)
 {
-       pte_t *pte = kmap_atomic(pmd_page(*dir), type) +
+       pte_t *pte = kmap_atomic(pmd_page(*dir)) +
                (pmd_ptfn(*dir) << HV_LOG2_PAGE_TABLE_ALIGN) & ~PAGE_MASK;
        return &pte[pte_index(address)];
 }
index 908ea5464a518097958083156eb5b0b94f4d021c..fb8b376bf28cb3e04a6bb903900f32838ab02a14 100644 (file)
@@ -720,7 +720,7 @@ static void rmap_remove(struct kvm *kvm, u64 *spte)
        }
 }
 
-static void set_spte_track_bits(u64 *sptep, u64 new_spte)
+static int set_spte_track_bits(u64 *sptep, u64 new_spte)
 {
        pfn_t pfn;
        u64 old_spte = *sptep;
@@ -731,19 +731,20 @@ static void set_spte_track_bits(u64 *sptep, u64 new_spte)
                old_spte = __xchg_spte(sptep, new_spte);
 
        if (!is_rmap_spte(old_spte))
-               return;
+               return 0;
 
        pfn = spte_to_pfn(old_spte);
        if (!shadow_accessed_mask || old_spte & shadow_accessed_mask)
                kvm_set_pfn_accessed(pfn);
        if (!shadow_dirty_mask || (old_spte & shadow_dirty_mask))
                kvm_set_pfn_dirty(pfn);
+       return 1;
 }
 
 static void drop_spte(struct kvm *kvm, u64 *sptep, u64 new_spte)
 {
-       set_spte_track_bits(sptep, new_spte);
-       rmap_remove(kvm, sptep);
+       if (set_spte_track_bits(sptep, new_spte))
+               rmap_remove(kvm, sptep);
 }
 
 static u64 *rmap_next(struct kvm *kvm, unsigned long *rmapp, u64 *spte)
index 2288ad829b327bb68d0efa65c104dcc7f2bbe7b5..cdac9e592aa53ee84b7e184900601ab4730354e5 100644 (file)
@@ -2560,6 +2560,7 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
                !kvm_exception_is_soft(vcpu->arch.exception.nr);
        events->exception.nr = vcpu->arch.exception.nr;
        events->exception.has_error_code = vcpu->arch.exception.has_error_code;
+       events->exception.pad = 0;
        events->exception.error_code = vcpu->arch.exception.error_code;
 
        events->interrupt.injected =
@@ -2573,12 +2574,14 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
        events->nmi.injected = vcpu->arch.nmi_injected;
        events->nmi.pending = vcpu->arch.nmi_pending;
        events->nmi.masked = kvm_x86_ops->get_nmi_mask(vcpu);
+       events->nmi.pad = 0;
 
        events->sipi_vector = vcpu->arch.sipi_vector;
 
        events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
                         | KVM_VCPUEVENT_VALID_SIPI_VECTOR
                         | KVM_VCPUEVENT_VALID_SHADOW);
+       memset(&events->reserved, 0, sizeof(events->reserved));
 }
 
 static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
@@ -2623,6 +2626,7 @@ static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu,
        dbgregs->dr6 = vcpu->arch.dr6;
        dbgregs->dr7 = vcpu->arch.dr7;
        dbgregs->flags = 0;
+       memset(&dbgregs->reserved, 0, sizeof(dbgregs->reserved));
 }
 
 static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
@@ -3106,6 +3110,7 @@ static int kvm_vm_ioctl_get_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
                sizeof(ps->channels));
        ps->flags = kvm->arch.vpit->pit_state.flags;
        mutex_unlock(&kvm->arch.vpit->pit_state.lock);
+       memset(&ps->reserved, 0, sizeof(ps->reserved));
        return r;
 }
 
@@ -3169,10 +3174,6 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
                struct kvm_memslots *slots, *old_slots;
                unsigned long *dirty_bitmap;
 
-               spin_lock(&kvm->mmu_lock);
-               kvm_mmu_slot_remove_write_access(kvm, log->slot);
-               spin_unlock(&kvm->mmu_lock);
-
                r = -ENOMEM;
                dirty_bitmap = vmalloc(n);
                if (!dirty_bitmap)
@@ -3194,6 +3195,10 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
                dirty_bitmap = old_slots->memslots[log->slot].dirty_bitmap;
                kfree(old_slots);
 
+               spin_lock(&kvm->mmu_lock);
+               kvm_mmu_slot_remove_write_access(kvm, log->slot);
+               spin_unlock(&kvm->mmu_lock);
+
                r = -EFAULT;
                if (copy_to_user(log->dirty_bitmap, dirty_bitmap, n)) {
                        vfree(dirty_bitmap);
@@ -3486,6 +3491,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
                user_ns.clock = kvm->arch.kvmclock_offset + now_ns;
                local_irq_enable();
                user_ns.flags = 0;
+               memset(&user_ns.pad, 0, sizeof(user_ns.pad));
 
                r = -EFAULT;
                if (copy_to_user(argp, &user_ns, sizeof(user_ns)))
@@ -3972,8 +3978,10 @@ int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu)
                return X86EMUL_CONTINUE;
 
        if (kvm_x86_ops->has_wbinvd_exit()) {
+               preempt_disable();
                smp_call_function_many(vcpu->arch.wbinvd_dirty_mask,
                                wbinvd_ipi, NULL, 1);
+               preempt_enable();
                cpumask_clear(vcpu->arch.wbinvd_dirty_mask);
        }
        wbinvd();
index 14cf9077bb2bcf4f01025518b11b0e87e072e9b5..f3ebb30f1b7fd9c7ed93d6328dbe4d8c54b1fd87 100644 (file)
@@ -26,6 +26,7 @@ obj-$(CONFIG_REGULATOR)               += regulator/
 
 # char/ comes before serial/ etc so that the VT console is the boot-time
 # default.
+obj-y                          += tty/
 obj-y                          += char/
 
 # gpu/ comes after char for AGP vs DRM startup
index 767107cce982bfdcb651797eb2fb634dde4f2356..3951020e494ac803001083b186a5b7614eb6d42f 100644 (file)
@@ -4363,9 +4363,9 @@ out_unreg_blkdev:
 out_put_disk:
        while (dr--) {
                del_timer(&motor_off_timer[dr]);
-               put_disk(disks[dr]);
                if (disks[dr]->queue)
                        blk_cleanup_queue(disks[dr]->queue);
+               put_disk(disks[dr]);
        }
        return err;
 }
@@ -4573,8 +4573,8 @@ static void __exit floppy_module_exit(void)
                        device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
                        platform_device_unregister(&floppy_device[drive]);
                }
-               put_disk(disks[drive]);
                blk_cleanup_queue(disks[drive]->queue);
+               put_disk(disks[drive]);
        }
 
        del_timer_sync(&fd_timeout);
diff --git a/drivers/char/.gitignore b/drivers/char/.gitignore
deleted file mode 100644 (file)
index 83683a2..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-consolemap_deftbl.c
-defkeymap.c
index 3a9c01416839ebc785abcdec1405135fce3df817..ba53ec956c95627ff03695a3bbb363f9f5f2f400 100644 (file)
@@ -2,24 +2,10 @@
 # Makefile for the kernel character device drivers.
 #
 
-#
-# This file contains the font map for the default (hardware) font
-#
-FONTMAPFILE = cp437.uni
-
-obj-y   += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o
-
-obj-y                          += tty_mutex.o
-obj-$(CONFIG_LEGACY_PTYS)      += pty.o
-obj-$(CONFIG_UNIX98_PTYS)      += pty.o
+obj-y                          += mem.o random.o
 obj-$(CONFIG_TTY_PRINTK)       += ttyprintk.o
 obj-y                          += misc.o
-obj-$(CONFIG_VT)               += vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)   += bfin_jtag_comm.o
-obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
-obj-$(CONFIG_HW_CONSOLE)       += vt.o defkeymap.o
-obj-$(CONFIG_AUDIT)            += tty_audit.o
-obj-$(CONFIG_MAGIC_SYSRQ)      += sysrq.o
 obj-$(CONFIG_MVME147_SCC)      += generic_serial.o vme_scc.o
 obj-$(CONFIG_MVME162_SCC)      += generic_serial.o vme_scc.o
 obj-$(CONFIG_BVME6000_SCC)     += generic_serial.o vme_scc.o
@@ -41,8 +27,6 @@ obj-$(CONFIG_ISI)             += isicom.o
 obj-$(CONFIG_SYNCLINK)         += synclink.o
 obj-$(CONFIG_SYNCLINKMP)       += synclinkmp.o
 obj-$(CONFIG_SYNCLINK_GT)      += synclink_gt.o
-obj-$(CONFIG_N_HDLC)           += n_hdlc.o
-obj-$(CONFIG_N_GSM)            += n_gsm.o
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
 obj-$(CONFIG_SX)               += sx.o generic_serial.o
 obj-$(CONFIG_RIO)              += rio/ generic_serial.o
@@ -74,7 +58,6 @@ obj-$(CONFIG_PRINTER)         += lp.o
 obj-$(CONFIG_APM_EMULATION)    += apm-emulation.o
 
 obj-$(CONFIG_DTLK)             += dtlk.o
-obj-$(CONFIG_R3964)            += n_r3964.o
 obj-$(CONFIG_APPLICOM)         += applicom.o
 obj-$(CONFIG_SONYPI)           += sonypi.o
 obj-$(CONFIG_RTC)              += rtc.o
@@ -115,28 +98,3 @@ obj-$(CONFIG_RAMOOPS)               += ramoops.o
 
 obj-$(CONFIG_JS_RTC)           += js-rtc.o
 js-rtc-y = rtc.o
-
-# Files generated that shall be removed upon make clean
-clean-files := consolemap_deftbl.c defkeymap.c
-
-quiet_cmd_conmk = CONMK   $@
-      cmd_conmk = scripts/conmakehash $< > $@
-
-$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE)
-       $(call cmd,conmk)
-
-$(obj)/defkeymap.o:  $(obj)/defkeymap.c
-
-# Uncomment if you're changing the keymap and have an appropriate
-# loadkeys version for the map. By default, we'll use the shipped
-# versions.
-# GENERATE_KEYMAP := 1
-
-ifdef GENERATE_KEYMAP
-
-$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
-       loadkeys --mktable $< > $@.tmp
-       sed -e 's/^static *//' $@.tmp > $@
-       rm $@.tmp
-
-endif
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
deleted file mode 100644 (file)
index 45d3e80..0000000
+++ /dev/null
@@ -1,745 +0,0 @@
-/*
- * consolemap.c
- *
- * Mapping from internal code (such as Latin-1 or Unicode or IBM PC code)
- * to font positions.
- *
- * aeb, 950210
- *
- * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998
- *
- * Fix bug in inverse translation. Stanislav Voronyi <stas@cnti.uanet.kharkov.ua>, Dec 1998
- */
-
-#include <linux/module.h>
-#include <linux/kd.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <asm/uaccess.h>
-#include <linux/consolemap.h>
-#include <linux/vt_kern.h>
-
-static unsigned short translations[][256] = {
-  /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
-  {
-    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
-    0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
-    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
-    0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
-    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
-    0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
-    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
-    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
-    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
-    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
-    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
-    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
-    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
-    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
-    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
-    0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
-    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
-    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
-    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
-    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
-    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
-    0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
-    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
-    0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
-    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
-    0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
-    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
-    0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
-    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
-    0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
-    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
-    0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
-  }, 
-  /* VT100 graphics mapped to Unicode */
-  {
-    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
-    0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
-    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
-    0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
-    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
-    0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
-    0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
-    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
-    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
-    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
-    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
-    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
-    0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
-    0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
-    0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
-    0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
-    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
-    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
-    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
-    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
-    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
-    0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
-    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
-    0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
-    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
-    0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
-    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
-    0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
-    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
-    0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
-    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
-    0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
-  },
-  /* IBM Codepage 437 mapped to Unicode */
-  {
-    0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 
-    0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
-    0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
-    0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
-    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
-    0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
-    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
-    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
-    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
-    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
-    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
-    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
-    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
-    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
-    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
-    0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
-    0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
-    0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
-    0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
-    0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
-    0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
-    0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
-    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
-    0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
-    0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
-    0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
-    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
-    0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
-    0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
-    0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
-    0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
-    0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
-  }, 
-  /* User mapping -- default to codes for direct font mapping */
-  {
-    0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007,
-    0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f,
-    0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017,
-    0xf018, 0xf019, 0xf01a, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
-    0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027,
-    0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02d, 0xf02e, 0xf02f,
-    0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
-    0xf038, 0xf039, 0xf03a, 0xf03b, 0xf03c, 0xf03d, 0xf03e, 0xf03f,
-    0xf040, 0xf041, 0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047,
-    0xf048, 0xf049, 0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f,
-    0xf050, 0xf051, 0xf052, 0xf053, 0xf054, 0xf055, 0xf056, 0xf057,
-    0xf058, 0xf059, 0xf05a, 0xf05b, 0xf05c, 0xf05d, 0xf05e, 0xf05f,
-    0xf060, 0xf061, 0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067,
-    0xf068, 0xf069, 0xf06a, 0xf06b, 0xf06c, 0xf06d, 0xf06e, 0xf06f,
-    0xf070, 0xf071, 0xf072, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077,
-    0xf078, 0xf079, 0xf07a, 0xf07b, 0xf07c, 0xf07d, 0xf07e, 0xf07f,
-    0xf080, 0xf081, 0xf082, 0xf083, 0xf084, 0xf085, 0xf086, 0xf087,
-    0xf088, 0xf089, 0xf08a, 0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f,
-    0xf090, 0xf091, 0xf092, 0xf093, 0xf094, 0xf095, 0xf096, 0xf097,
-    0xf098, 0xf099, 0xf09a, 0xf09b, 0xf09c, 0xf09d, 0xf09e, 0xf09f,
-    0xf0a0, 0xf0a1, 0xf0a2, 0xf0a3, 0xf0a4, 0xf0a5, 0xf0a6, 0xf0a7,
-    0xf0a8, 0xf0a9, 0xf0aa, 0xf0ab, 0xf0ac, 0xf0ad, 0xf0ae, 0xf0af,
-    0xf0b0, 0xf0b1, 0xf0b2, 0xf0b3, 0xf0b4, 0xf0b5, 0xf0b6, 0xf0b7,
-    0xf0b8, 0xf0b9, 0xf0ba, 0xf0bb, 0xf0bc, 0xf0bd, 0xf0be, 0xf0bf,
-    0xf0c0, 0xf0c1, 0xf0c2, 0xf0c3, 0xf0c4, 0xf0c5, 0xf0c6, 0xf0c7,
-    0xf0c8, 0xf0c9, 0xf0ca, 0xf0cb, 0xf0cc, 0xf0cd, 0xf0ce, 0xf0cf,
-    0xf0d0, 0xf0d1, 0xf0d2, 0xf0d3, 0xf0d4, 0xf0d5, 0xf0d6, 0xf0d7,
-    0xf0d8, 0xf0d9, 0xf0da, 0xf0db, 0xf0dc, 0xf0dd, 0xf0de, 0xf0df,
-    0xf0e0, 0xf0e1, 0xf0e2, 0xf0e3, 0xf0e4, 0xf0e5, 0xf0e6, 0xf0e7,
-    0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef,
-    0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7,
-    0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff
-  }
-};
-
-/* The standard kernel character-to-font mappings are not invertible
-   -- this is just a best effort. */
-
-#define MAX_GLYPH 512          /* Max possible glyph value */
-
-static int inv_translate[MAX_NR_CONSOLES];
-
-struct uni_pagedir {
-       u16             **uni_pgdir[32];
-       unsigned long   refcount;
-       unsigned long   sum;
-       unsigned char   *inverse_translations[4];
-       u16             *inverse_trans_unicode;
-       int             readonly;
-};
-
-static struct uni_pagedir *dflt;
-
-static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i)
-{
-       int j, glyph;
-       unsigned short *t = translations[i];
-       unsigned char *q;
-       
-       if (!p) return;
-       q = p->inverse_translations[i];
-
-       if (!q) {
-               q = p->inverse_translations[i] = (unsigned char *) 
-                       kmalloc(MAX_GLYPH, GFP_KERNEL);
-               if (!q) return;
-       }
-       memset(q, 0, MAX_GLYPH);
-
-       for (j = 0; j < E_TABSZ; j++) {
-               glyph = conv_uni_to_pc(conp, t[j]);
-               if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) {
-                       /* prefer '-' above SHY etc. */
-                       q[glyph] = j;
-               }
-       }
-}
-
-static void set_inverse_trans_unicode(struct vc_data *conp,
-                                     struct uni_pagedir *p)
-{
-       int i, j, k, glyph;
-       u16 **p1, *p2;
-       u16 *q;
-
-       if (!p) return;
-       q = p->inverse_trans_unicode;
-       if (!q) {
-               q = p->inverse_trans_unicode =
-                       kmalloc(MAX_GLYPH * sizeof(u16), GFP_KERNEL);
-               if (!q)
-                       return;
-       }
-       memset(q, 0, MAX_GLYPH * sizeof(u16));
-
-       for (i = 0; i < 32; i++) {
-               p1 = p->uni_pgdir[i];
-               if (!p1)
-                       continue;
-               for (j = 0; j < 32; j++) {
-                       p2 = p1[j];
-                       if (!p2)
-                               continue;
-                       for (k = 0; k < 64; k++) {
-                               glyph = p2[k];
-                               if (glyph >= 0 && glyph < MAX_GLYPH
-                                              && q[glyph] < 32)
-                                       q[glyph] = (i << 11) + (j << 6) + k;
-                       }
-               }
-       }
-}
-
-unsigned short *set_translate(int m, struct vc_data *vc)
-{
-       inv_translate[vc->vc_num] = m;
-       return translations[m];
-}
-
-/*
- * Inverse translation is impossible for several reasons:
- * 1. The font<->character maps are not 1-1.
- * 2. The text may have been written while a different translation map
- *    was active.
- * Still, it is now possible to a certain extent to cut and paste non-ASCII.
- */
-u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
-{
-       struct uni_pagedir *p;
-       int m;
-       if (glyph < 0 || glyph >= MAX_GLYPH)
-               return 0;
-       else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
-               return glyph;
-       else if (use_unicode) {
-               if (!p->inverse_trans_unicode)
-                       return glyph;
-               else
-                       return p->inverse_trans_unicode[glyph];
-       } else {
-               m = inv_translate[conp->vc_num];
-               if (!p->inverse_translations[m])
-                       return glyph;
-               else
-                       return p->inverse_translations[m][glyph];
-       }
-}
-EXPORT_SYMBOL_GPL(inverse_translate);
-
-static void update_user_maps(void)
-{
-       int i;
-       struct uni_pagedir *p, *q = NULL;
-       
-       for (i = 0; i < MAX_NR_CONSOLES; i++) {
-               if (!vc_cons_allocated(i))
-                       continue;
-               p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
-               if (p && p != q) {
-                       set_inverse_transl(vc_cons[i].d, p, USER_MAP);
-                       set_inverse_trans_unicode(vc_cons[i].d, p);
-                       q = p;
-               }
-       }
-}
-
-/*
- * Load customizable translation table
- * arg points to a 256 byte translation table.
- *
- * The "old" variants are for translation directly to font (using the
- * 0xf000-0xf0ff "transparent" Unicodes) whereas the "new" variants set
- * Unicodes explicitly.
- */
-int con_set_trans_old(unsigned char __user * arg)
-{
-       int i;
-       unsigned short *p = translations[USER_MAP];
-
-       if (!access_ok(VERIFY_READ, arg, E_TABSZ))
-               return -EFAULT;
-
-       for (i=0; i<E_TABSZ ; i++) {
-               unsigned char uc;
-               __get_user(uc, arg+i);
-               p[i] = UNI_DIRECT_BASE | uc;
-       }
-
-       update_user_maps();
-       return 0;
-}
-
-int con_get_trans_old(unsigned char __user * arg)
-{
-       int i, ch;
-       unsigned short *p = translations[USER_MAP];
-
-       if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
-               return -EFAULT;
-
-       for (i=0; i<E_TABSZ ; i++)
-         {
-           ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
-           __put_user((ch & ~0xff) ? 0 : ch, arg+i);
-         }
-       return 0;
-}
-
-int con_set_trans_new(ushort __user * arg)
-{
-       int i;
-       unsigned short *p = translations[USER_MAP];
-
-       if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
-               return -EFAULT;
-
-       for (i=0; i<E_TABSZ ; i++) {
-               unsigned short us;
-               __get_user(us, arg+i);
-               p[i] = us;
-       }
-
-       update_user_maps();
-       return 0;
-}
-
-int con_get_trans_new(ushort __user * arg)
-{
-       int i;
-       unsigned short *p = translations[USER_MAP];
-
-       if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
-               return -EFAULT;
-
-       for (i=0; i<E_TABSZ ; i++)
-         __put_user(p[i], arg+i);
-       
-       return 0;
-}
-
-/*
- * Unicode -> current font conversion 
- *
- * A font has at most 512 chars, usually 256.
- * But one font position may represent several Unicode chars.
- * A hashtable is somewhat of a pain to deal with, so use a
- * "paged table" instead.  Simulation has shown the memory cost of
- * this 3-level paged table scheme to be comparable to a hash table.
- */
-
-extern u8 dfont_unicount[];    /* Defined in console_defmap.c */
-extern u16 dfont_unitable[];
-
-static void con_release_unimap(struct uni_pagedir *p)
-{
-       u16 **p1;
-       int i, j;
-
-       if (p == dflt) dflt = NULL;  
-       for (i = 0; i < 32; i++) {
-               if ((p1 = p->uni_pgdir[i]) != NULL) {
-                       for (j = 0; j < 32; j++)
-                               kfree(p1[j]);
-                       kfree(p1);
-               }
-               p->uni_pgdir[i] = NULL;
-       }
-       for (i = 0; i < 4; i++) {
-               kfree(p->inverse_translations[i]);
-               p->inverse_translations[i] = NULL;
-       }
-       if (p->inverse_trans_unicode) {
-               kfree(p->inverse_trans_unicode);
-               p->inverse_trans_unicode = NULL;
-       }
-}
-
-void con_free_unimap(struct vc_data *vc)
-{
-       struct uni_pagedir *p;
-
-       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-       if (!p)
-               return;
-       *vc->vc_uni_pagedir_loc = 0;
-       if (--p->refcount)
-               return;
-       con_release_unimap(p);
-       kfree(p);
-}
-  
-static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
-{
-       int i, j, k;
-       struct uni_pagedir *q;
-       
-       for (i = 0; i < MAX_NR_CONSOLES; i++) {
-               if (!vc_cons_allocated(i))
-                       continue;
-               q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
-               if (!q || q == p || q->sum != p->sum)
-                       continue;
-               for (j = 0; j < 32; j++) {
-                       u16 **p1, **q1;
-                       p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
-                       if (!p1 && !q1)
-                               continue;
-                       if (!p1 || !q1)
-                               break;
-                       for (k = 0; k < 32; k++) {
-                               if (!p1[k] && !q1[k])
-                                       continue;
-                               if (!p1[k] || !q1[k])
-                                       break;
-                               if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
-                                       break;
-                       }
-                       if (k < 32)
-                               break;
-               }
-               if (j == 32) {
-                       q->refcount++;
-                       *conp->vc_uni_pagedir_loc = (unsigned long)q;
-                       con_release_unimap(p);
-                       kfree(p);
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-static int
-con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
-{
-       int i, n;
-       u16 **p1, *p2;
-
-       if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
-               p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
-               if (!p1) return -ENOMEM;
-               for (i = 0; i < 32; i++)
-                       p1[i] = NULL;
-       }
-
-       if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
-               p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
-               if (!p2) return -ENOMEM;
-               memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
-       }
-
-       p2[unicode & 0x3f] = fontpos;
-       
-       p->sum += (fontpos << 20) + unicode;
-
-       return 0;
-}
-
-/* ui is a leftover from using a hashtable, but might be used again */
-int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
-{
-       struct uni_pagedir *p, *q;
-  
-       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-       if (p && p->readonly) return -EIO;
-       if (!p || --p->refcount) {
-               q = kzalloc(sizeof(*p), GFP_KERNEL);
-               if (!q) {
-                       if (p) p->refcount++;
-                       return -ENOMEM;
-               }
-               q->refcount=1;
-               *vc->vc_uni_pagedir_loc = (unsigned long)q;
-       } else {
-               if (p == dflt) dflt = NULL;
-               p->refcount++;
-               p->sum = 0;
-               con_release_unimap(p);
-       }
-       return 0;
-}
-
-int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
-{
-       int err = 0, err1, i;
-       struct uni_pagedir *p, *q;
-
-       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-       if (p->readonly) return -EIO;
-       
-       if (!ct) return 0;
-       
-       if (p->refcount > 1) {
-               int j, k;
-               u16 **p1, *p2, l;
-               
-               err1 = con_clear_unimap(vc, NULL);
-               if (err1) return err1;
-               
-               q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-               for (i = 0, l = 0; i < 32; i++)
-               if ((p1 = p->uni_pgdir[i]))
-                       for (j = 0; j < 32; j++)
-                       if ((p2 = p1[j]))
-                               for (k = 0; k < 64; k++, l++)
-                               if (p2[k] != 0xffff) {
-                                       err1 = con_insert_unipair(q, l, p2[k]);
-                                       if (err1) {
-                                               p->refcount++;
-                                               *vc->vc_uni_pagedir_loc = (unsigned long)p;
-                                               con_release_unimap(q);
-                                               kfree(q);
-                                               return err1; 
-                                       }
-                               }
-               p = q;
-       } else if (p == dflt)
-               dflt = NULL;
-       
-       while (ct--) {
-               unsigned short unicode, fontpos;
-               __get_user(unicode, &list->unicode);
-               __get_user(fontpos, &list->fontpos);
-               if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
-                       err = err1;
-               list++;
-       }
-       
-       if (con_unify_unimap(vc, p))
-               return err;
-
-       for (i = 0; i <= 3; i++)
-               set_inverse_transl(vc, p, i); /* Update all inverse translations */
-       set_inverse_trans_unicode(vc, p);
-  
-       return err;
-}
-
-/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
-   The representation used was the most compact I could come up
-   with.  This routine is executed at sys_setup time, and when the
-   PIO_FONTRESET ioctl is called. */
-
-int con_set_default_unimap(struct vc_data *vc)
-{
-       int i, j, err = 0, err1;
-       u16 *q;
-       struct uni_pagedir *p;
-
-       if (dflt) {
-               p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-               if (p == dflt)
-                       return 0;
-               dflt->refcount++;
-               *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
-               if (p && --p->refcount) {
-                       con_release_unimap(p);
-                       kfree(p);
-               }
-               return 0;
-       }
-       
-       /* The default font is always 256 characters */
-
-       err = con_clear_unimap(vc, NULL);
-       if (err) return err;
-    
-       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-       q = dfont_unitable;
-       
-       for (i = 0; i < 256; i++)
-               for (j = dfont_unicount[i]; j; j--) {
-                       err1 = con_insert_unipair(p, *(q++), i);
-                       if (err1)
-                               err = err1;
-               }
-                       
-       if (con_unify_unimap(vc, p)) {
-               dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-               return err;
-       }
-
-       for (i = 0; i <= 3; i++)
-               set_inverse_transl(vc, p, i);   /* Update all inverse translations */
-       set_inverse_trans_unicode(vc, p);
-       dflt = p;
-       return err;
-}
-EXPORT_SYMBOL(con_set_default_unimap);
-
-int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
-{
-       struct uni_pagedir *q;
-
-       if (!*src_vc->vc_uni_pagedir_loc)
-               return -EINVAL;
-       if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
-               return 0;
-       con_free_unimap(dst_vc);
-       q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
-       q->refcount++;
-       *dst_vc->vc_uni_pagedir_loc = (long)q;
-       return 0;
-}
-
-int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
-{
-       int i, j, k, ect;
-       u16 **p1, *p2;
-       struct uni_pagedir *p;
-
-       ect = 0;
-       if (*vc->vc_uni_pagedir_loc) {
-               p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-               for (i = 0; i < 32; i++)
-               if ((p1 = p->uni_pgdir[i]))
-                       for (j = 0; j < 32; j++)
-                       if ((p2 = *(p1++)))
-                               for (k = 0; k < 64; k++) {
-                                       if (*p2 < MAX_GLYPH && ect++ < ct) {
-                                               __put_user((u_short)((i<<11)+(j<<6)+k),
-                                                          &list->unicode);
-                                               __put_user((u_short) *p2, 
-                                                          &list->fontpos);
-                                               list++;
-                                       }
-                                       p2++;
-                               }
-       }
-       __put_user(ect, uct);
-       return ((ect <= ct) ? 0 : -ENOMEM);
-}
-
-void con_protect_unimap(struct vc_data *vc, int rdonly)
-{
-       struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-       
-       if (p)
-               p->readonly = rdonly;
-}
-
-/*
- * Always use USER_MAP. These functions are used by the keyboard,
- * which shouldn't be affected by G0/G1 switching, etc.
- * If the user map still contains default values, i.e. the
- * direct-to-font mapping, then assume user is using Latin1.
- */
-/* may be called during an interrupt */
-u32 conv_8bit_to_uni(unsigned char c)
-{
-       unsigned short uni = translations[USER_MAP][c];
-       return uni == (0xf000 | c) ? c : uni;
-}
-
-int conv_uni_to_8bit(u32 uni)
-{
-       int c;
-       for (c = 0; c < 0x100; c++)
-               if (translations[USER_MAP][c] == uni ||
-                  (translations[USER_MAP][c] == (c | 0xf000) && uni == c))
-                       return c;
-       return -1;
-}
-
-int
-conv_uni_to_pc(struct vc_data *conp, long ucs) 
-{
-       int h;
-       u16 **p1, *p2;
-       struct uni_pagedir *p;
-  
-       /* Only 16-bit codes supported at this time */
-       if (ucs > 0xffff)
-               return -4;              /* Not found */
-       else if (ucs < 0x20)
-               return -1;              /* Not a printable character */
-       else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
-               return -2;                      /* Zero-width space */
-       /*
-        * UNI_DIRECT_BASE indicates the start of the region in the User Zone
-        * which always has a 1:1 mapping to the currently loaded font.  The
-        * UNI_DIRECT_MASK indicates the bit span of the region.
-        */
-       else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
-               return ucs & UNI_DIRECT_MASK;
-  
-       if (!*conp->vc_uni_pagedir_loc)
-               return -3;
-
-       p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;  
-       if ((p1 = p->uni_pgdir[ucs >> 11]) &&
-           (p2 = p1[(ucs >> 6) & 0x1f]) &&
-           (h = p2[ucs & 0x3f]) < MAX_GLYPH)
-               return h;
-
-       return -4;              /* not found */
-}
-
-/*
- * This is called at sys_setup time, after memory and the console are
- * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
- * from this function, hence the call from sys_setup.
- */
-void __init 
-console_map_init(void)
-{
-       int i;
-       
-       for (i = 0; i < MAX_NR_CONSOLES; i++)
-               if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
-                       con_set_default_unimap(vc_cons[i].d);
-}
-
-EXPORT_SYMBOL(con_copy_unimap);
diff --git a/drivers/char/cp437.uni b/drivers/char/cp437.uni
deleted file mode 100644 (file)
index bc61634..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-#
-# Unicode table for IBM Codepage 437.  Note that there are many more
-# substitutions that could be conceived (for example, thick-line
-# graphs probably should be replaced with double-line ones, accented
-# Latin characters should replaced with their nonaccented versions,
-# and some upper case Greek characters could be replaced by Latin), however,
-# I have limited myself to the Unicodes used by the kernel ISO 8859-1,
-# DEC VT, and IBM CP 437 tables.
-#
-# --------------------------------
-#
-# Basic IBM dingbats, some of which will never have a purpose clear
-# to mankind
-#
-0x00   U+0000
-0x01   U+263a
-0x02   U+263b
-0x03   U+2665
-0x04   U+2666 U+25c6
-0x05   U+2663
-0x06   U+2660
-0x07   U+2022
-0x08   U+25d8
-0x09   U+25cb
-0x0a   U+25d9
-0x0b   U+2642
-0x0c   U+2640
-0x0d   U+266a
-0x0e   U+266b
-0x0f   U+263c U+00a4
-0x10   U+25b6 U+25ba
-0x11   U+25c0 U+25c4
-0x12   U+2195
-0x13   U+203c
-0x14   U+00b6
-0x15   U+00a7
-0x16   U+25ac
-0x17   U+21a8
-0x18   U+2191
-0x19   U+2193
-0x1a   U+2192
-0x1b   U+2190
-0x1c   U+221f
-0x1d   U+2194
-0x1e   U+25b2
-0x1f   U+25bc
-#
-# The ASCII range is identity-mapped, but some of the characters also
-# have to act as substitutes, especially the upper-case characters.
-#
-0x20   U+0020
-0x21   U+0021
-0x22   U+0022 U+00a8
-0x23   U+0023
-0x24   U+0024
-0x25   U+0025
-0x26   U+0026
-0x27   U+0027 U+00b4
-0x28   U+0028
-0x29   U+0029
-0x2a   U+002a
-0x2b   U+002b
-0x2c   U+002c U+00b8
-0x2d   U+002d U+00ad
-0x2e   U+002e
-0x2f   U+002f
-0x30   U+0030
-0x31   U+0031
-0x32   U+0032
-0x33   U+0033
-0x34   U+0034
-0x35   U+0035
-0x36   U+0036
-0x37   U+0037
-0x38   U+0038
-0x39   U+0039
-0x3a   U+003a
-0x3b   U+003b
-0x3c   U+003c
-0x3d   U+003d
-0x3e   U+003e
-0x3f   U+003f
-0x40   U+0040
-0x41   U+0041 U+00c0 U+00c1 U+00c2 U+00c3
-0x42   U+0042
-0x43   U+0043 U+00a9
-0x44   U+0044 U+00d0
-0x45   U+0045 U+00c8 U+00ca U+00cb
-0x46   U+0046
-0x47   U+0047
-0x48   U+0048
-0x49   U+0049 U+00cc U+00cd U+00ce U+00cf
-0x4a   U+004a
-0x4b   U+004b U+212a
-0x4c   U+004c
-0x4d   U+004d
-0x4e   U+004e
-0x4f   U+004f U+00d2 U+00d3 U+00d4 U+00d5
-0x50   U+0050
-0x51   U+0051
-0x52   U+0052 U+00ae
-0x53   U+0053
-0x54   U+0054
-0x55   U+0055 U+00d9 U+00da U+00db
-0x56   U+0056
-0x57   U+0057
-0x58   U+0058
-0x59   U+0059 U+00dd
-0x5a   U+005a
-0x5b   U+005b
-0x5c   U+005c
-0x5d   U+005d
-0x5e   U+005e
-0x5f   U+005f U+23bd U+f804
-0x60   U+0060
-0x61   U+0061 U+00e3
-0x62   U+0062
-0x63   U+0063
-0x64   U+0064
-0x65   U+0065
-0x66   U+0066
-0x67   U+0067
-0x68   U+0068
-0x69   U+0069
-0x6a   U+006a
-0x6b   U+006b
-0x6c   U+006c
-0x6d   U+006d
-0x6e   U+006e
-0x6f   U+006f U+00f5
-0x70   U+0070
-0x71   U+0071
-0x72   U+0072
-0x73   U+0073
-0x74   U+0074
-0x75   U+0075
-0x76   U+0076
-0x77   U+0077
-0x78   U+0078 U+00d7
-0x79   U+0079 U+00fd
-0x7a   U+007a
-0x7b   U+007b
-0x7c   U+007c U+00a6
-0x7d   U+007d
-0x7e   U+007e
-#
-# Okay, what on Earth is this one supposed to be used for?
-#
-0x7f   U+2302
-#
-# Non-English characters, mostly lower case letters...
-#
-0x80   U+00c7
-0x81   U+00fc
-0x82   U+00e9
-0x83   U+00e2
-0x84   U+00e4
-0x85   U+00e0
-0x86   U+00e5
-0x87   U+00e7
-0x88   U+00ea
-0x89   U+00eb
-0x8a   U+00e8
-0x8b   U+00ef
-0x8c   U+00ee
-0x8d   U+00ec
-0x8e   U+00c4
-0x8f   U+00c5 U+212b
-0x90   U+00c9
-0x91   U+00e6
-0x92   U+00c6
-0x93   U+00f4
-0x94   U+00f6
-0x95   U+00f2
-0x96   U+00fb
-0x97   U+00f9
-0x98   U+00ff
-0x99   U+00d6
-0x9a   U+00dc
-0x9b   U+00a2
-0x9c   U+00a3
-0x9d   U+00a5
-0x9e   U+20a7
-0x9f   U+0192
-0xa0   U+00e1
-0xa1   U+00ed
-0xa2   U+00f3
-0xa3   U+00fa
-0xa4   U+00f1
-0xa5   U+00d1
-0xa6   U+00aa
-0xa7   U+00ba
-0xa8   U+00bf
-0xa9   U+2310
-0xaa   U+00ac
-0xab   U+00bd
-0xac   U+00bc
-0xad   U+00a1
-0xae   U+00ab
-0xaf   U+00bb
-#
-# Block graphics
-#
-0xb0   U+2591
-0xb1   U+2592
-0xb2   U+2593
-0xb3   U+2502
-0xb4   U+2524
-0xb5   U+2561
-0xb6   U+2562
-0xb7   U+2556
-0xb8   U+2555
-0xb9   U+2563
-0xba   U+2551
-0xbb   U+2557
-0xbc   U+255d
-0xbd   U+255c
-0xbe   U+255b
-0xbf   U+2510
-0xc0   U+2514
-0xc1   U+2534
-0xc2   U+252c
-0xc3   U+251c
-0xc4   U+2500
-0xc5   U+253c
-0xc6   U+255e
-0xc7   U+255f
-0xc8   U+255a
-0xc9   U+2554
-0xca   U+2569
-0xcb   U+2566
-0xcc   U+2560
-0xcd   U+2550
-0xce   U+256c
-0xcf   U+2567
-0xd0   U+2568
-0xd1   U+2564
-0xd2   U+2565
-0xd3   U+2559
-0xd4   U+2558
-0xd5   U+2552
-0xd6   U+2553
-0xd7   U+256b
-0xd8   U+256a
-0xd9   U+2518
-0xda   U+250c
-0xdb   U+2588
-0xdc   U+2584
-0xdd   U+258c
-0xde   U+2590
-0xdf   U+2580
-#
-# Greek letters and mathematical symbols
-#
-0xe0   U+03b1
-0xe1   U+03b2 U+00df
-0xe2   U+0393
-0xe3   U+03c0
-0xe4   U+03a3
-0xe5   U+03c3
-0xe6   U+00b5 U+03bc
-0xe7   U+03c4
-0xe8   U+03a6 U+00d8
-0xe9   U+0398
-0xea   U+03a9 U+2126
-0xeb   U+03b4 U+00f0
-0xec   U+221e
-0xed   U+03c6 U+00f8
-0xee   U+03b5 U+2208
-0xef   U+2229
-0xf0   U+2261
-0xf1   U+00b1
-0xf2   U+2265
-0xf3   U+2264
-0xf4   U+2320
-0xf5   U+2321
-0xf6   U+00f7
-0xf7   U+2248
-0xf8   U+00b0
-0xf9   U+2219
-0xfa   U+00b7
-0xfb   U+221a
-0xfc   U+207f
-0xfd   U+00b2
-#
-# Square bullet, non-spacing blank
-# Mapping U+fffd to the square bullet means it is the substitution
-# character
-# 
-0xfe   U+25a0 U+fffd
-0xff   U+00a0
diff --git a/drivers/char/defkeymap.c_shipped b/drivers/char/defkeymap.c_shipped
deleted file mode 100644 (file)
index d2208df..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-/* Do not edit this file! It was automatically generated by   */
-/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
-
-#include <linux/types.h>
-#include <linux/keyboard.h>
-#include <linux/kd.h>
-
-u_short plain_map[NR_KEYS] = {
-       0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
-       0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf07f, 0xf009,
-       0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
-       0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73,
-       0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
-       0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
-       0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf30c,
-       0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
-       0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf209, 0xf307,
-       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
-       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03c, 0xf10a,
-       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short shift_map[NR_KEYS] = {
-       0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e,
-       0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07f, 0xf009,
-       0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
-       0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201, 0xf702, 0xfb41, 0xfb53,
-       0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a,
-       0xf022, 0xf07e, 0xf700, 0xf07c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56,
-       0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf30c,
-       0xf703, 0xf020, 0xf207, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e,
-       0xf10f, 0xf110, 0xf111, 0xf112, 0xf113, 0xf213, 0xf203, 0xf307,
-       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
-       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03e, 0xf10a,
-       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf20b, 0xf601, 0xf602, 0xf117, 0xf600, 0xf20a, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short altgr_map[NR_KEYS] = {
-       0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
-       0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200,
-       0xfb71, 0xfb77, 0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
-       0xfb6f, 0xfb70, 0xf200, 0xf07e, 0xf201, 0xf702, 0xf914, 0xfb73,
-       0xf917, 0xf919, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf200,
-       0xf200, 0xf200, 0xf700, 0xf200, 0xfb7a, 0xfb78, 0xf916, 0xfb76,
-       0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
-       0xf703, 0xf200, 0xf207, 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510,
-       0xf511, 0xf512, 0xf513, 0xf514, 0xf515, 0xf208, 0xf202, 0xf911,
-       0xf912, 0xf913, 0xf30b, 0xf90e, 0xf90f, 0xf910, 0xf30a, 0xf90b,
-       0xf90c, 0xf90d, 0xf90a, 0xf310, 0xf206, 0xf200, 0xf07c, 0xf516,
-       0xf517, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short ctrl_map[NR_KEYS] = {
-       0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
-       0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
-       0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
-       0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013,
-       0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
-       0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016,
-       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf700, 0xf30c,
-       0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
-       0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf204, 0xf307,
-       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
-       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf10a,
-       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short shift_ctrl_map[NR_KEYS] = {
-       0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200,
-       0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
-       0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013,
-       0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
-       0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016,
-       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
-       0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xf307,
-       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
-       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short alt_map[NR_KEYS] = {
-       0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836,
-       0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf87f, 0xf809,
-       0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
-       0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d, 0xf702, 0xf861, 0xf873,
-       0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b,
-       0xf827, 0xf860, 0xf700, 0xf85c, 0xf87a, 0xf878, 0xf863, 0xf876,
-       0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf30c,
-       0xf703, 0xf820, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504,
-       0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf209, 0xf907,
-       0xf908, 0xf909, 0xf30b, 0xf904, 0xf905, 0xf906, 0xf30a, 0xf901,
-       0xf902, 0xf903, 0xf900, 0xf310, 0xf206, 0xf200, 0xf83c, 0xf50a,
-       0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf210, 0xf211, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short ctrl_alt_map[NR_KEYS] = {
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809,
-       0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813,
-       0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200,
-       0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816,
-       0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
-       0xf703, 0xf200, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504,
-       0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf200, 0xf307,
-       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
-       0xf302, 0xf303, 0xf300, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf50a,
-       0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-ushort *key_maps[MAX_NR_KEYMAPS] = {
-       plain_map, shift_map, altgr_map, NULL,
-       ctrl_map, shift_ctrl_map, NULL, NULL,
-       alt_map, NULL, NULL, NULL,
-       ctrl_alt_map, NULL
-};
-
-unsigned int keymap_count = 7;
-
-/*
- * Philosophy: most people do not define more strings, but they who do
- * often want quite a lot of string space. So, we statically allocate
- * the default and allocate dynamically in chunks of 512 bytes.
- */
-
-char func_buf[] = {
-       '\033', '[', '[', 'A', 0, 
-       '\033', '[', '[', 'B', 0, 
-       '\033', '[', '[', 'C', 0, 
-       '\033', '[', '[', 'D', 0, 
-       '\033', '[', '[', 'E', 0, 
-       '\033', '[', '1', '7', '~', 0, 
-       '\033', '[', '1', '8', '~', 0, 
-       '\033', '[', '1', '9', '~', 0, 
-       '\033', '[', '2', '0', '~', 0, 
-       '\033', '[', '2', '1', '~', 0, 
-       '\033', '[', '2', '3', '~', 0, 
-       '\033', '[', '2', '4', '~', 0, 
-       '\033', '[', '2', '5', '~', 0, 
-       '\033', '[', '2', '6', '~', 0, 
-       '\033', '[', '2', '8', '~', 0, 
-       '\033', '[', '2', '9', '~', 0, 
-       '\033', '[', '3', '1', '~', 0, 
-       '\033', '[', '3', '2', '~', 0, 
-       '\033', '[', '3', '3', '~', 0, 
-       '\033', '[', '3', '4', '~', 0, 
-       '\033', '[', '1', '~', 0, 
-       '\033', '[', '2', '~', 0, 
-       '\033', '[', '3', '~', 0, 
-       '\033', '[', '4', '~', 0, 
-       '\033', '[', '5', '~', 0, 
-       '\033', '[', '6', '~', 0, 
-       '\033', '[', 'M', 0, 
-       '\033', '[', 'P', 0, 
-};
-
-char *funcbufptr = func_buf;
-int funcbufsize = sizeof(func_buf);
-int funcbufleft = 0;          /* space left */
-
-char *func_table[MAX_NR_FUNC] = {
-       func_buf + 0,
-       func_buf + 5,
-       func_buf + 10,
-       func_buf + 15,
-       func_buf + 20,
-       func_buf + 25,
-       func_buf + 31,
-       func_buf + 37,
-       func_buf + 43,
-       func_buf + 49,
-       func_buf + 55,
-       func_buf + 61,
-       func_buf + 67,
-       func_buf + 73,
-       func_buf + 79,
-       func_buf + 85,
-       func_buf + 91,
-       func_buf + 97,
-       func_buf + 103,
-       func_buf + 109,
-       func_buf + 115,
-       func_buf + 120,
-       func_buf + 125,
-       func_buf + 130,
-       func_buf + 135,
-       func_buf + 140,
-       func_buf + 145,
-       NULL,
-       NULL,
-       func_buf + 149,
-       NULL,
-};
-
-struct kbdiacruc accent_table[MAX_DIACR] = {
-       {'`', 'A', 0300},       {'`', 'a', 0340},
-       {'\'', 'A', 0301},      {'\'', 'a', 0341},
-       {'^', 'A', 0302},       {'^', 'a', 0342},
-       {'~', 'A', 0303},       {'~', 'a', 0343},
-       {'"', 'A', 0304},       {'"', 'a', 0344},
-       {'O', 'A', 0305},       {'o', 'a', 0345},
-       {'0', 'A', 0305},       {'0', 'a', 0345},
-       {'A', 'A', 0305},       {'a', 'a', 0345},
-       {'A', 'E', 0306},       {'a', 'e', 0346},
-       {',', 'C', 0307},       {',', 'c', 0347},
-       {'`', 'E', 0310},       {'`', 'e', 0350},
-       {'\'', 'E', 0311},      {'\'', 'e', 0351},
-       {'^', 'E', 0312},       {'^', 'e', 0352},
-       {'"', 'E', 0313},       {'"', 'e', 0353},
-       {'`', 'I', 0314},       {'`', 'i', 0354},
-       {'\'', 'I', 0315},      {'\'', 'i', 0355},
-       {'^', 'I', 0316},       {'^', 'i', 0356},
-       {'"', 'I', 0317},       {'"', 'i', 0357},
-       {'-', 'D', 0320},       {'-', 'd', 0360},
-       {'~', 'N', 0321},       {'~', 'n', 0361},
-       {'`', 'O', 0322},       {'`', 'o', 0362},
-       {'\'', 'O', 0323},      {'\'', 'o', 0363},
-       {'^', 'O', 0324},       {'^', 'o', 0364},
-       {'~', 'O', 0325},       {'~', 'o', 0365},
-       {'"', 'O', 0326},       {'"', 'o', 0366},
-       {'/', 'O', 0330},       {'/', 'o', 0370},
-       {'`', 'U', 0331},       {'`', 'u', 0371},
-       {'\'', 'U', 0332},      {'\'', 'u', 0372},
-       {'^', 'U', 0333},       {'^', 'u', 0373},
-       {'"', 'U', 0334},       {'"', 'u', 0374},
-       {'\'', 'Y', 0335},      {'\'', 'y', 0375},
-       {'T', 'H', 0336},       {'t', 'h', 0376},
-       {'s', 's', 0337},       {'"', 'y', 0377},
-       {'s', 'z', 0337},       {'i', 'j', 0377},
-};
-
-unsigned int accent_table_size = 68;
diff --git a/drivers/char/defkeymap.map b/drivers/char/defkeymap.map
deleted file mode 100644 (file)
index 50b30ca..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-# Default kernel keymap. This uses 7 modifier combinations.
-keymaps 0-2,4-5,8,12
-# Change the above line into
-#      keymaps 0-2,4-6,8,12
-# in case you want the entries
-#      altgr   control keycode  83 = Boot            
-#      altgr   control keycode 111 = Boot            
-# below.
-#
-# In fact AltGr is used very little, and one more keymap can
-# be saved by mapping AltGr to Alt (and adapting a few entries):
-# keycode 100 = Alt
-#
-keycode   1 = Escape           Escape          
-       alt     keycode   1 = Meta_Escape     
-keycode   2 = one              exclam          
-       alt     keycode   2 = Meta_one        
-keycode   3 = two              at               at              
-       control keycode   3 = nul             
-       shift   control keycode   3 = nul             
-       alt     keycode   3 = Meta_two        
-keycode   4 = three            numbersign      
-       control keycode   4 = Escape          
-       alt     keycode   4 = Meta_three      
-keycode   5 = four             dollar           dollar          
-       control keycode   5 = Control_backslash
-       alt     keycode   5 = Meta_four       
-keycode   6 = five             percent         
-       control keycode   6 = Control_bracketright
-       alt     keycode   6 = Meta_five       
-keycode   7 = six              asciicircum     
-       control keycode   7 = Control_asciicircum
-       alt     keycode   7 = Meta_six        
-keycode   8 = seven            ampersand        braceleft       
-       control keycode   8 = Control_underscore
-       alt     keycode   8 = Meta_seven      
-keycode   9 = eight            asterisk         bracketleft     
-       control keycode   9 = Delete          
-       alt     keycode   9 = Meta_eight      
-keycode  10 = nine             parenleft        bracketright    
-       alt     keycode  10 = Meta_nine       
-keycode  11 = zero             parenright       braceright      
-       alt     keycode  11 = Meta_zero       
-keycode  12 = minus            underscore       backslash       
-       control keycode  12 = Control_underscore
-       shift   control keycode  12 = Control_underscore
-       alt     keycode  12 = Meta_minus      
-keycode  13 = equal            plus            
-       alt     keycode  13 = Meta_equal      
-keycode  14 = Delete           Delete          
-       control keycode  14 = BackSpace
-       alt     keycode  14 = Meta_Delete     
-keycode  15 = Tab              Tab             
-       alt     keycode  15 = Meta_Tab        
-keycode  16 = q               
-keycode  17 = w               
-keycode  18 = e
-       altgr   keycode  18 = Hex_E   
-keycode  19 = r               
-keycode  20 = t               
-keycode  21 = y               
-keycode  22 = u               
-keycode  23 = i               
-keycode  24 = o               
-keycode  25 = p               
-keycode  26 = bracketleft      braceleft       
-       control keycode  26 = Escape          
-       alt     keycode  26 = Meta_bracketleft
-keycode  27 = bracketright     braceright       asciitilde      
-       control keycode  27 = Control_bracketright
-       alt     keycode  27 = Meta_bracketright
-keycode  28 = Return          
-       alt     keycode  28 = Meta_Control_m  
-keycode  29 = Control         
-keycode  30 = a
-       altgr   keycode  30 = Hex_A
-keycode  31 = s               
-keycode  32 = d
-       altgr   keycode  32 = Hex_D   
-keycode  33 = f
-       altgr   keycode  33 = Hex_F               
-keycode  34 = g               
-keycode  35 = h               
-keycode  36 = j               
-keycode  37 = k               
-keycode  38 = l               
-keycode  39 = semicolon        colon           
-       alt     keycode  39 = Meta_semicolon  
-keycode  40 = apostrophe       quotedbl        
-       control keycode  40 = Control_g       
-       alt     keycode  40 = Meta_apostrophe 
-keycode  41 = grave            asciitilde      
-       control keycode  41 = nul             
-       alt     keycode  41 = Meta_grave      
-keycode  42 = Shift           
-keycode  43 = backslash        bar             
-       control keycode  43 = Control_backslash
-       alt     keycode  43 = Meta_backslash  
-keycode  44 = z               
-keycode  45 = x               
-keycode  46 = c
-       altgr   keycode  46 = Hex_C   
-keycode  47 = v               
-keycode  48 = b
-       altgr   keycode  48 = Hex_B
-keycode  49 = n               
-keycode  50 = m               
-keycode  51 = comma            less            
-       alt     keycode  51 = Meta_comma      
-keycode  52 = period           greater         
-       control keycode  52 = Compose         
-       alt     keycode  52 = Meta_period     
-keycode  53 = slash            question        
-       control keycode  53 = Delete          
-       alt     keycode  53 = Meta_slash      
-keycode  54 = Shift           
-keycode  55 = KP_Multiply     
-keycode  56 = Alt             
-keycode  57 = space            space           
-       control keycode  57 = nul             
-       alt     keycode  57 = Meta_space      
-keycode  58 = Caps_Lock       
-keycode  59 = F1               F11              Console_13      
-       control keycode  59 = F1              
-       alt     keycode  59 = Console_1       
-       control alt     keycode  59 = Console_1       
-keycode  60 = F2               F12              Console_14      
-       control keycode  60 = F2              
-       alt     keycode  60 = Console_2       
-       control alt     keycode  60 = Console_2       
-keycode  61 = F3               F13              Console_15      
-       control keycode  61 = F3              
-       alt     keycode  61 = Console_3       
-       control alt     keycode  61 = Console_3       
-keycode  62 = F4               F14              Console_16      
-       control keycode  62 = F4              
-       alt     keycode  62 = Console_4       
-       control alt     keycode  62 = Console_4       
-keycode  63 = F5               F15              Console_17      
-       control keycode  63 = F5              
-       alt     keycode  63 = Console_5       
-       control alt     keycode  63 = Console_5       
-keycode  64 = F6               F16              Console_18      
-       control keycode  64 = F6              
-       alt     keycode  64 = Console_6       
-       control alt     keycode  64 = Console_6       
-keycode  65 = F7               F17              Console_19      
-       control keycode  65 = F7              
-       alt     keycode  65 = Console_7       
-       control alt     keycode  65 = Console_7       
-keycode  66 = F8               F18              Console_20      
-       control keycode  66 = F8              
-       alt     keycode  66 = Console_8       
-       control alt     keycode  66 = Console_8       
-keycode  67 = F9               F19              Console_21      
-       control keycode  67 = F9              
-       alt     keycode  67 = Console_9       
-       control alt     keycode  67 = Console_9       
-keycode  68 = F10              F20              Console_22      
-       control keycode  68 = F10             
-       alt     keycode  68 = Console_10      
-       control alt     keycode  68 = Console_10      
-keycode  69 = Num_Lock
-       shift   keycode  69 = Bare_Num_Lock
-keycode  70 = Scroll_Lock      Show_Memory      Show_Registers  
-       control keycode  70 = Show_State      
-       alt     keycode  70 = Scroll_Lock     
-keycode  71 = KP_7            
-       alt     keycode  71 = Ascii_7         
-       altgr   keycode  71 = Hex_7         
-keycode  72 = KP_8            
-       alt     keycode  72 = Ascii_8         
-       altgr   keycode  72 = Hex_8         
-keycode  73 = KP_9            
-       alt     keycode  73 = Ascii_9         
-       altgr   keycode  73 = Hex_9         
-keycode  74 = KP_Subtract     
-keycode  75 = KP_4            
-       alt     keycode  75 = Ascii_4         
-       altgr   keycode  75 = Hex_4         
-keycode  76 = KP_5            
-       alt     keycode  76 = Ascii_5         
-       altgr   keycode  76 = Hex_5         
-keycode  77 = KP_6            
-       alt     keycode  77 = Ascii_6         
-       altgr   keycode  77 = Hex_6         
-keycode  78 = KP_Add          
-keycode  79 = KP_1            
-       alt     keycode  79 = Ascii_1         
-       altgr   keycode  79 = Hex_1         
-keycode  80 = KP_2            
-       alt     keycode  80 = Ascii_2         
-       altgr   keycode  80 = Hex_2         
-keycode  81 = KP_3            
-       alt     keycode  81 = Ascii_3         
-       altgr   keycode  81 = Hex_3         
-keycode  82 = KP_0            
-       alt     keycode  82 = Ascii_0         
-       altgr   keycode  82 = Hex_0         
-keycode  83 = KP_Period       
-#      altgr   control keycode  83 = Boot            
-       control alt     keycode  83 = Boot            
-keycode  84 = Last_Console    
-keycode  85 =
-keycode  86 = less             greater          bar             
-       alt     keycode  86 = Meta_less       
-keycode  87 = F11              F11              Console_23      
-       control keycode  87 = F11             
-       alt     keycode  87 = Console_11      
-       control alt     keycode  87 = Console_11      
-keycode  88 = F12              F12              Console_24      
-       control keycode  88 = F12             
-       alt     keycode  88 = Console_12      
-       control alt     keycode  88 = Console_12      
-keycode  89 =
-keycode  90 =
-keycode  91 =
-keycode  92 =
-keycode  93 =
-keycode  94 =
-keycode  95 =
-keycode  96 = KP_Enter        
-keycode  97 = Control         
-keycode  98 = KP_Divide       
-keycode  99 = Control_backslash
-       control keycode  99 = Control_backslash
-       alt     keycode  99 = Control_backslash
-keycode 100 = AltGr           
-keycode 101 = Break           
-keycode 102 = Find            
-keycode 103 = Up              
-keycode 104 = Prior           
-       shift   keycode 104 = Scroll_Backward 
-keycode 105 = Left            
-       alt     keycode 105 = Decr_Console
-keycode 106 = Right           
-       alt     keycode 106 = Incr_Console
-keycode 107 = Select          
-keycode 108 = Down            
-keycode 109 = Next            
-       shift   keycode 109 = Scroll_Forward  
-keycode 110 = Insert          
-keycode 111 = Remove          
-#      altgr   control keycode 111 = Boot            
-       control alt     keycode 111 = Boot            
-keycode 112 = Macro           
-keycode 113 = F13             
-keycode 114 = F14             
-keycode 115 = Help            
-keycode 116 = Do              
-keycode 117 = F17             
-keycode 118 = KP_MinPlus      
-keycode 119 = Pause           
-keycode 120 =
-keycode 121 =
-keycode 122 =
-keycode 123 =
-keycode 124 =
-keycode 125 =
-keycode 126 =
-keycode 127 =
-string F1 = "\033[[A"
-string F2 = "\033[[B"
-string F3 = "\033[[C"
-string F4 = "\033[[D"
-string F5 = "\033[[E"
-string F6 = "\033[17~"
-string F7 = "\033[18~"
-string F8 = "\033[19~"
-string F9 = "\033[20~"
-string F10 = "\033[21~"
-string F11 = "\033[23~"
-string F12 = "\033[24~"
-string F13 = "\033[25~"
-string F14 = "\033[26~"
-string F15 = "\033[28~"
-string F16 = "\033[29~"
-string F17 = "\033[31~"
-string F18 = "\033[32~"
-string F19 = "\033[33~"
-string F20 = "\033[34~"
-string Find = "\033[1~"
-string Insert = "\033[2~"
-string Remove = "\033[3~"
-string Select = "\033[4~"
-string Prior = "\033[5~"
-string Next = "\033[6~"
-string Macro = "\033[M"
-string Pause = "\033[P"
-compose '`' 'A' to 'À'
-compose '`' 'a' to 'à'
-compose '\'' 'A' to 'Á'
-compose '\'' 'a' to 'á'
-compose '^' 'A' to 'Â'
-compose '^' 'a' to 'â'
-compose '~' 'A' to 'Ã'
-compose '~' 'a' to 'ã'
-compose '"' 'A' to 'Ä'
-compose '"' 'a' to 'ä'
-compose 'O' 'A' to 'Å'
-compose 'o' 'a' to 'å'
-compose '0' 'A' to 'Å'
-compose '0' 'a' to 'å'
-compose 'A' 'A' to 'Å'
-compose 'a' 'a' to 'å'
-compose 'A' 'E' to 'Æ'
-compose 'a' 'e' to 'æ'
-compose ',' 'C' to 'Ç'
-compose ',' 'c' to 'ç'
-compose '`' 'E' to 'È'
-compose '`' 'e' to 'è'
-compose '\'' 'E' to 'É'
-compose '\'' 'e' to 'é'
-compose '^' 'E' to 'Ê'
-compose '^' 'e' to 'ê'
-compose '"' 'E' to 'Ë'
-compose '"' 'e' to 'ë'
-compose '`' 'I' to 'Ì'
-compose '`' 'i' to 'ì'
-compose '\'' 'I' to 'Í'
-compose '\'' 'i' to 'í'
-compose '^' 'I' to 'Î'
-compose '^' 'i' to 'î'
-compose '"' 'I' to 'Ï'
-compose '"' 'i' to 'ï'
-compose '-' 'D' to 'Ð'
-compose '-' 'd' to 'ð'
-compose '~' 'N' to 'Ñ'
-compose '~' 'n' to 'ñ'
-compose '`' 'O' to 'Ò'
-compose '`' 'o' to 'ò'
-compose '\'' 'O' to 'Ó'
-compose '\'' 'o' to 'ó'
-compose '^' 'O' to 'Ô'
-compose '^' 'o' to 'ô'
-compose '~' 'O' to 'Õ'
-compose '~' 'o' to 'õ'
-compose '"' 'O' to 'Ö'
-compose '"' 'o' to 'ö'
-compose '/' 'O' to 'Ø'
-compose '/' 'o' to 'ø'
-compose '`' 'U' to 'Ù'
-compose '`' 'u' to 'ù'
-compose '\'' 'U' to 'Ú'
-compose '\'' 'u' to 'ú'
-compose '^' 'U' to 'Û'
-compose '^' 'u' to 'û'
-compose '"' 'U' to 'Ü'
-compose '"' 'u' to 'ü'
-compose '\'' 'Y' to 'Ý'
-compose '\'' 'y' to 'ý'
-compose 'T' 'H' to 'Þ'
-compose 't' 'h' to 'þ'
-compose 's' 's' to 'ß'
-compose '"' 'y' to 'ÿ'
-compose 's' 'z' to 'ß'
-compose 'i' 'j' to 'ÿ'
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
deleted file mode 100644 (file)
index e95d787..0000000
+++ /dev/null
@@ -1,1454 +0,0 @@
-/*
- * linux/drivers/char/keyboard.c
- *
- * Written for linux by Johan Myreen as a translation from
- * the assembly version by Linus (with diacriticals added)
- *
- * Some additional features added by Christoph Niemann (ChN), March 1993
- *
- * Loadable keymaps by Risto Kankkunen, May 1993
- *
- * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
- * Added decr/incr_console, dynamic keymaps, Unicode support,
- * dynamic function/string keys, led setting,  Sept 1994
- * `Sticky' modifier keys, 951006.
- *
- * 11-11-96: SAK should now work in the raw mode (Martin Mares)
- *
- * Modified to provide 'generic' keyboard support by Hamish Macdonald
- * Merge with the m68k keyboard driver and split-off of the PC low-level
- * parts by Geert Uytterhoeven, May 1997
- *
- * 27-05-97: Added support for the Magic SysRq Key (Martin Mares)
- * 30-07-98: Dead keys redone, aeb@cwi.nl.
- * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik)
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/consolemap.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/irq.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/kbd_diacr.h>
-#include <linux/vt_kern.h>
-#include <linux/input.h>
-#include <linux/reboot.h>
-#include <linux/notifier.h>
-#include <linux/jiffies.h>
-
-extern void ctrl_alt_del(void);
-
-/*
- * Exported functions/variables
- */
-
-#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
-
-/*
- * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
- * This seems a good reason to start with NumLock off. On HIL keyboards
- * of PARISC machines however there is no NumLock key and everyone expects the keypad
- * to be used for numbers.
- */
-
-#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
-#define KBD_DEFLEDS (1 << VC_NUMLOCK)
-#else
-#define KBD_DEFLEDS 0
-#endif
-
-#define KBD_DEFLOCK 0
-
-void compute_shiftstate(void);
-
-/*
- * Handler Tables.
- */
-
-#define K_HANDLERS\
-       k_self,         k_fn,           k_spec,         k_pad,\
-       k_dead,         k_cons,         k_cur,          k_shift,\
-       k_meta,         k_ascii,        k_lock,         k_lowercase,\
-       k_slock,        k_dead2,        k_brl,          k_ignore
-
-typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value,
-                           char up_flag);
-static k_handler_fn K_HANDLERS;
-static k_handler_fn *k_handler[16] = { K_HANDLERS };
-
-#define FN_HANDLERS\
-       fn_null,        fn_enter,       fn_show_ptregs, fn_show_mem,\
-       fn_show_state,  fn_send_intr,   fn_lastcons,    fn_caps_toggle,\
-       fn_num,         fn_hold,        fn_scroll_forw, fn_scroll_back,\
-       fn_boot_it,     fn_caps_on,     fn_compose,     fn_SAK,\
-       fn_dec_console, fn_inc_console, fn_spawn_con,   fn_bare_num
-
-typedef void (fn_handler_fn)(struct vc_data *vc);
-static fn_handler_fn FN_HANDLERS;
-static fn_handler_fn *fn_handler[] = { FN_HANDLERS };
-
-/*
- * Variables exported for vt_ioctl.c
- */
-
-/* maximum values each key_handler can handle */
-const int max_vals[] = {
-       255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
-       NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
-       255, NR_LOCK - 1, 255, NR_BRL - 1
-};
-
-const int NR_TYPES = ARRAY_SIZE(max_vals);
-
-struct kbd_struct kbd_table[MAX_NR_CONSOLES];
-EXPORT_SYMBOL_GPL(kbd_table);
-static struct kbd_struct *kbd = kbd_table;
-
-struct vt_spawn_console vt_spawn_con = {
-       .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock),
-       .pid  = NULL,
-       .sig  = 0,
-};
-
-/*
- * Variables exported for vt.c
- */
-
-int shift_state = 0;
-
-/*
- * Internal Data.
- */
-
-static struct input_handler kbd_handler;
-static DEFINE_SPINLOCK(kbd_event_lock);
-static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
-static unsigned char shift_down[NR_SHIFT];             /* shift state counters.. */
-static bool dead_key_next;
-static int npadch = -1;                                        /* -1 or number assembled on pad */
-static unsigned int diacr;
-static char rep;                                       /* flag telling character repeat */
-
-static unsigned char ledstate = 0xff;                  /* undefined */
-static unsigned char ledioctl;
-
-static struct ledptr {
-       unsigned int *addr;
-       unsigned int mask;
-       unsigned char valid:1;
-} ledptrs[3];
-
-/*
- * Notifier list for console keyboard events
- */
-static ATOMIC_NOTIFIER_HEAD(keyboard_notifier_list);
-
-int register_keyboard_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_register(&keyboard_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(register_keyboard_notifier);
-
-int unregister_keyboard_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_unregister(&keyboard_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_keyboard_notifier);
-
-/*
- * Translation of scancodes to keycodes. We set them on only the first
- * keyboard in the list that accepts the scancode and keycode.
- * Explanation for not choosing the first attached keyboard anymore:
- *  USB keyboards for example have two event devices: one for all "normal"
- *  keys and one for extra function keys (like "volume up", "make coffee",
- *  etc.). So this means that scancodes for the extra function keys won't
- *  be valid for the first event device, but will be for the second.
- */
-
-struct getset_keycode_data {
-       struct input_keymap_entry ke;
-       int error;
-};
-
-static int getkeycode_helper(struct input_handle *handle, void *data)
-{
-       struct getset_keycode_data *d = data;
-
-       d->error = input_get_keycode(handle->dev, &d->ke);
-
-       return d->error == 0; /* stop as soon as we successfully get one */
-}
-
-int getkeycode(unsigned int scancode)
-{
-       struct getset_keycode_data d = {
-               .ke     = {
-                       .flags          = 0,
-                       .len            = sizeof(scancode),
-                       .keycode        = 0,
-               },
-               .error  = -ENODEV,
-       };
-
-       memcpy(d.ke.scancode, &scancode, sizeof(scancode));
-
-       input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper);
-
-       return d.error ?: d.ke.keycode;
-}
-
-static int setkeycode_helper(struct input_handle *handle, void *data)
-{
-       struct getset_keycode_data *d = data;
-
-       d->error = input_set_keycode(handle->dev, &d->ke);
-
-       return d->error == 0; /* stop as soon as we successfully set one */
-}
-
-int setkeycode(unsigned int scancode, unsigned int keycode)
-{
-       struct getset_keycode_data d = {
-               .ke     = {
-                       .flags          = 0,
-                       .len            = sizeof(scancode),
-                       .keycode        = keycode,
-               },
-               .error  = -ENODEV,
-       };
-
-       memcpy(d.ke.scancode, &scancode, sizeof(scancode));
-
-       input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper);
-
-       return d.error;
-}
-
-/*
- * Making beeps and bells. Note that we prefer beeps to bells, but when
- * shutting the sound off we do both.
- */
-
-static int kd_sound_helper(struct input_handle *handle, void *data)
-{
-       unsigned int *hz = data;
-       struct input_dev *dev = handle->dev;
-
-       if (test_bit(EV_SND, dev->evbit)) {
-               if (test_bit(SND_TONE, dev->sndbit)) {
-                       input_inject_event(handle, EV_SND, SND_TONE, *hz);
-                       if (*hz)
-                               return 0;
-               }
-               if (test_bit(SND_BELL, dev->sndbit))
-                       input_inject_event(handle, EV_SND, SND_BELL, *hz ? 1 : 0);
-       }
-
-       return 0;
-}
-
-static void kd_nosound(unsigned long ignored)
-{
-       static unsigned int zero;
-
-       input_handler_for_each_handle(&kbd_handler, &zero, kd_sound_helper);
-}
-
-static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0);
-
-void kd_mksound(unsigned int hz, unsigned int ticks)
-{
-       del_timer_sync(&kd_mksound_timer);
-
-       input_handler_for_each_handle(&kbd_handler, &hz, kd_sound_helper);
-
-       if (hz && ticks)
-               mod_timer(&kd_mksound_timer, jiffies + ticks);
-}
-EXPORT_SYMBOL(kd_mksound);
-
-/*
- * Setting the keyboard rate.
- */
-
-static int kbd_rate_helper(struct input_handle *handle, void *data)
-{
-       struct input_dev *dev = handle->dev;
-       struct kbd_repeat *rep = data;
-
-       if (test_bit(EV_REP, dev->evbit)) {
-
-               if (rep[0].delay > 0)
-                       input_inject_event(handle,
-                                          EV_REP, REP_DELAY, rep[0].delay);
-               if (rep[0].period > 0)
-                       input_inject_event(handle,
-                                          EV_REP, REP_PERIOD, rep[0].period);
-
-               rep[1].delay = dev->rep[REP_DELAY];
-               rep[1].period = dev->rep[REP_PERIOD];
-       }
-
-       return 0;
-}
-
-int kbd_rate(struct kbd_repeat *rep)
-{
-       struct kbd_repeat data[2] = { *rep };
-
-       input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper);
-       *rep = data[1]; /* Copy currently used settings */
-
-       return 0;
-}
-
-/*
- * Helper Functions.
- */
-static void put_queue(struct vc_data *vc, int ch)
-{
-       struct tty_struct *tty = vc->port.tty;
-
-       if (tty) {
-               tty_insert_flip_char(tty, ch, 0);
-               con_schedule_flip(tty);
-       }
-}
-
-static void puts_queue(struct vc_data *vc, char *cp)
-{
-       struct tty_struct *tty = vc->port.tty;
-
-       if (!tty)
-               return;
-
-       while (*cp) {
-               tty_insert_flip_char(tty, *cp, 0);
-               cp++;
-       }
-       con_schedule_flip(tty);
-}
-
-static void applkey(struct vc_data *vc, int key, char mode)
-{
-       static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
-
-       buf[1] = (mode ? 'O' : '[');
-       buf[2] = key;
-       puts_queue(vc, buf);
-}
-
-/*
- * Many other routines do put_queue, but I think either
- * they produce ASCII, or they produce some user-assigned
- * string, and in both cases we might assume that it is
- * in utf-8 already.
- */
-static void to_utf8(struct vc_data *vc, uint c)
-{
-       if (c < 0x80)
-               /*  0******* */
-               put_queue(vc, c);
-       else if (c < 0x800) {
-               /* 110***** 10****** */
-               put_queue(vc, 0xc0 | (c >> 6));
-               put_queue(vc, 0x80 | (c & 0x3f));
-       } else if (c < 0x10000) {
-               if (c >= 0xD800 && c < 0xE000)
-                       return;
-               if (c == 0xFFFF)
-                       return;
-               /* 1110**** 10****** 10****** */
-               put_queue(vc, 0xe0 | (c >> 12));
-               put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
-               put_queue(vc, 0x80 | (c & 0x3f));
-       } else if (c < 0x110000) {
-               /* 11110*** 10****** 10****** 10****** */
-               put_queue(vc, 0xf0 | (c >> 18));
-               put_queue(vc, 0x80 | ((c >> 12) & 0x3f));
-               put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
-               put_queue(vc, 0x80 | (c & 0x3f));
-       }
-}
-
-/*
- * Called after returning from RAW mode or when changing consoles - recompute
- * shift_down[] and shift_state from key_down[] maybe called when keymap is
- * undefined, so that shiftkey release is seen
- */
-void compute_shiftstate(void)
-{
-       unsigned int i, j, k, sym, val;
-
-       shift_state = 0;
-       memset(shift_down, 0, sizeof(shift_down));
-
-       for (i = 0; i < ARRAY_SIZE(key_down); i++) {
-
-               if (!key_down[i])
-                       continue;
-
-               k = i * BITS_PER_LONG;
-
-               for (j = 0; j < BITS_PER_LONG; j++, k++) {
-
-                       if (!test_bit(k, key_down))
-                               continue;
-
-                       sym = U(key_maps[0][k]);
-                       if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
-                               continue;
-
-                       val = KVAL(sym);
-                       if (val == KVAL(K_CAPSSHIFT))
-                               val = KVAL(K_SHIFT);
-
-                       shift_down[val]++;
-                       shift_state |= (1 << val);
-               }
-       }
-}
-
-/*
- * We have a combining character DIACR here, followed by the character CH.
- * If the combination occurs in the table, return the corresponding value.
- * Otherwise, if CH is a space or equals DIACR, return DIACR.
- * Otherwise, conclude that DIACR was not combining after all,
- * queue it and return CH.
- */
-static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch)
-{
-       unsigned int d = diacr;
-       unsigned int i;
-
-       diacr = 0;
-
-       if ((d & ~0xff) == BRL_UC_ROW) {
-               if ((ch & ~0xff) == BRL_UC_ROW)
-                       return d | ch;
-       } else {
-               for (i = 0; i < accent_table_size; i++)
-                       if (accent_table[i].diacr == d && accent_table[i].base == ch)
-                               return accent_table[i].result;
-       }
-
-       if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d)
-               return d;
-
-       if (kbd->kbdmode == VC_UNICODE)
-               to_utf8(vc, d);
-       else {
-               int c = conv_uni_to_8bit(d);
-               if (c != -1)
-                       put_queue(vc, c);
-       }
-
-       return ch;
-}
-
-/*
- * Special function handlers
- */
-static void fn_enter(struct vc_data *vc)
-{
-       if (diacr) {
-               if (kbd->kbdmode == VC_UNICODE)
-                       to_utf8(vc, diacr);
-               else {
-                       int c = conv_uni_to_8bit(diacr);
-                       if (c != -1)
-                               put_queue(vc, c);
-               }
-               diacr = 0;
-       }
-
-       put_queue(vc, 13);
-       if (vc_kbd_mode(kbd, VC_CRLF))
-               put_queue(vc, 10);
-}
-
-static void fn_caps_toggle(struct vc_data *vc)
-{
-       if (rep)
-               return;
-
-       chg_vc_kbd_led(kbd, VC_CAPSLOCK);
-}
-
-static void fn_caps_on(struct vc_data *vc)
-{
-       if (rep)
-               return;
-
-       set_vc_kbd_led(kbd, VC_CAPSLOCK);
-}
-
-static void fn_show_ptregs(struct vc_data *vc)
-{
-       struct pt_regs *regs = get_irq_regs();
-
-       if (regs)
-               show_regs(regs);
-}
-
-static void fn_hold(struct vc_data *vc)
-{
-       struct tty_struct *tty = vc->port.tty;
-
-       if (rep || !tty)
-               return;
-
-       /*
-        * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
-        * these routines are also activated by ^S/^Q.
-        * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
-        */
-       if (tty->stopped)
-               start_tty(tty);
-       else
-               stop_tty(tty);
-}
-
-static void fn_num(struct vc_data *vc)
-{
-       if (vc_kbd_mode(kbd, VC_APPLIC))
-               applkey(vc, 'P', 1);
-       else
-               fn_bare_num(vc);
-}
-
-/*
- * Bind this to Shift-NumLock if you work in application keypad mode
- * but want to be able to change the NumLock flag.
- * Bind this to NumLock if you prefer that the NumLock key always
- * changes the NumLock flag.
- */
-static void fn_bare_num(struct vc_data *vc)
-{
-       if (!rep)
-               chg_vc_kbd_led(kbd, VC_NUMLOCK);
-}
-
-static void fn_lastcons(struct vc_data *vc)
-{
-       /* switch to the last used console, ChN */
-       set_console(last_console);
-}
-
-static void fn_dec_console(struct vc_data *vc)
-{
-       int i, cur = fg_console;
-
-       /* Currently switching?  Queue this next switch relative to that. */
-       if (want_console != -1)
-               cur = want_console;
-
-       for (i = cur - 1; i != cur; i--) {
-               if (i == -1)
-                       i = MAX_NR_CONSOLES - 1;
-               if (vc_cons_allocated(i))
-                       break;
-       }
-       set_console(i);
-}
-
-static void fn_inc_console(struct vc_data *vc)
-{
-       int i, cur = fg_console;
-
-       /* Currently switching?  Queue this next switch relative to that. */
-       if (want_console != -1)
-               cur = want_console;
-
-       for (i = cur+1; i != cur; i++) {
-               if (i == MAX_NR_CONSOLES)
-                       i = 0;
-               if (vc_cons_allocated(i))
-                       break;
-       }
-       set_console(i);
-}
-
-static void fn_send_intr(struct vc_data *vc)
-{
-       struct tty_struct *tty = vc->port.tty;
-
-       if (!tty)
-               return;
-       tty_insert_flip_char(tty, 0, TTY_BREAK);
-       con_schedule_flip(tty);
-}
-
-static void fn_scroll_forw(struct vc_data *vc)
-{
-       scrollfront(vc, 0);
-}
-
-static void fn_scroll_back(struct vc_data *vc)
-{
-       scrollback(vc, 0);
-}
-
-static void fn_show_mem(struct vc_data *vc)
-{
-       show_mem();
-}
-
-static void fn_show_state(struct vc_data *vc)
-{
-       show_state();
-}
-
-static void fn_boot_it(struct vc_data *vc)
-{
-       ctrl_alt_del();
-}
-
-static void fn_compose(struct vc_data *vc)
-{
-       dead_key_next = true;
-}
-
-static void fn_spawn_con(struct vc_data *vc)
-{
-       spin_lock(&vt_spawn_con.lock);
-       if (vt_spawn_con.pid)
-               if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) {
-                       put_pid(vt_spawn_con.pid);
-                       vt_spawn_con.pid = NULL;
-               }
-       spin_unlock(&vt_spawn_con.lock);
-}
-
-static void fn_SAK(struct vc_data *vc)
-{
-       struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
-       schedule_work(SAK_work);
-}
-
-static void fn_null(struct vc_data *vc)
-{
-       compute_shiftstate();
-}
-
-/*
- * Special key handlers
- */
-static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag)
-{
-}
-
-static void k_spec(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       if (up_flag)
-               return;
-       if (value >= ARRAY_SIZE(fn_handler))
-               return;
-       if ((kbd->kbdmode == VC_RAW ||
-            kbd->kbdmode == VC_MEDIUMRAW) &&
-            value != KVAL(K_SAK))
-               return;         /* SAK is allowed even in raw mode */
-       fn_handler[value](vc);
-}
-
-static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       pr_err("k_lowercase was called - impossible\n");
-}
-
-static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag)
-{
-       if (up_flag)
-               return;         /* no action, if this is a key release */
-
-       if (diacr)
-               value = handle_diacr(vc, value);
-
-       if (dead_key_next) {
-               dead_key_next = false;
-               diacr = value;
-               return;
-       }
-       if (kbd->kbdmode == VC_UNICODE)
-               to_utf8(vc, value);
-       else {
-               int c = conv_uni_to_8bit(value);
-               if (c != -1)
-                       put_queue(vc, c);
-       }
-}
-
-/*
- * Handle dead key. Note that we now may have several
- * dead keys modifying the same character. Very useful
- * for Vietnamese.
- */
-static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag)
-{
-       if (up_flag)
-               return;
-
-       diacr = (diacr ? handle_diacr(vc, value) : value);
-}
-
-static void k_self(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       k_unicode(vc, conv_8bit_to_uni(value), up_flag);
-}
-
-static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       k_deadunicode(vc, value, up_flag);
-}
-
-/*
- * Obsolete - for backwards compatibility only
- */
-static void k_dead(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
-
-       k_deadunicode(vc, ret_diacr[value], up_flag);
-}
-
-static void k_cons(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       if (up_flag)
-               return;
-
-       set_console(value);
-}
-
-static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       if (up_flag)
-               return;
-
-       if ((unsigned)value < ARRAY_SIZE(func_table)) {
-               if (func_table[value])
-                       puts_queue(vc, func_table[value]);
-       } else
-               pr_err("k_fn called with value=%d\n", value);
-}
-
-static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       static const char cur_chars[] = "BDCA";
-
-       if (up_flag)
-               return;
-
-       applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
-}
-
-static void k_pad(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       static const char pad_chars[] = "0123456789+-*/\015,.?()#";
-       static const char app_map[] = "pqrstuvwxylSRQMnnmPQS";
-
-       if (up_flag)
-               return;         /* no action, if this is a key release */
-
-       /* kludge... shift forces cursor/number keys */
-       if (vc_kbd_mode(kbd, VC_APPLIC) && !shift_down[KG_SHIFT]) {
-               applkey(vc, app_map[value], 1);
-               return;
-       }
-
-       if (!vc_kbd_led(kbd, VC_NUMLOCK)) {
-
-               switch (value) {
-               case KVAL(K_PCOMMA):
-               case KVAL(K_PDOT):
-                       k_fn(vc, KVAL(K_REMOVE), 0);
-                       return;
-               case KVAL(K_P0):
-                       k_fn(vc, KVAL(K_INSERT), 0);
-                       return;
-               case KVAL(K_P1):
-                       k_fn(vc, KVAL(K_SELECT), 0);
-                       return;
-               case KVAL(K_P2):
-                       k_cur(vc, KVAL(K_DOWN), 0);
-                       return;
-               case KVAL(K_P3):
-                       k_fn(vc, KVAL(K_PGDN), 0);
-                       return;
-               case KVAL(K_P4):
-                       k_cur(vc, KVAL(K_LEFT), 0);
-                       return;
-               case KVAL(K_P6):
-                       k_cur(vc, KVAL(K_RIGHT), 0);
-                       return;
-               case KVAL(K_P7):
-                       k_fn(vc, KVAL(K_FIND), 0);
-                       return;
-               case KVAL(K_P8):
-                       k_cur(vc, KVAL(K_UP), 0);
-                       return;
-               case KVAL(K_P9):
-                       k_fn(vc, KVAL(K_PGUP), 0);
-                       return;
-               case KVAL(K_P5):
-                       applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC));
-                       return;
-               }
-       }
-
-       put_queue(vc, pad_chars[value]);
-       if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
-               put_queue(vc, 10);
-}
-
-static void k_shift(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       int old_state = shift_state;
-
-       if (rep)
-               return;
-       /*
-        * Mimic typewriter:
-        * a CapsShift key acts like Shift but undoes CapsLock
-        */
-       if (value == KVAL(K_CAPSSHIFT)) {
-               value = KVAL(K_SHIFT);
-               if (!up_flag)
-                       clr_vc_kbd_led(kbd, VC_CAPSLOCK);
-       }
-
-       if (up_flag) {
-               /*
-                * handle the case that two shift or control
-                * keys are depressed simultaneously
-                */
-               if (shift_down[value])
-                       shift_down[value]--;
-       } else
-               shift_down[value]++;
-
-       if (shift_down[value])
-               shift_state |= (1 << value);
-       else
-               shift_state &= ~(1 << value);
-
-       /* kludge */
-       if (up_flag && shift_state != old_state && npadch != -1) {
-               if (kbd->kbdmode == VC_UNICODE)
-                       to_utf8(vc, npadch);
-               else
-                       put_queue(vc, npadch & 0xff);
-               npadch = -1;
-       }
-}
-
-static void k_meta(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       if (up_flag)
-               return;
-
-       if (vc_kbd_mode(kbd, VC_META)) {
-               put_queue(vc, '\033');
-               put_queue(vc, value);
-       } else
-               put_queue(vc, value | 0x80);
-}
-
-static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       int base;
-
-       if (up_flag)
-               return;
-
-       if (value < 10) {
-               /* decimal input of code, while Alt depressed */
-               base = 10;
-       } else {
-               /* hexadecimal input of code, while AltGr depressed */
-               value -= 10;
-               base = 16;
-       }
-
-       if (npadch == -1)
-               npadch = value;
-       else
-               npadch = npadch * base + value;
-}
-
-static void k_lock(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       if (up_flag || rep)
-               return;
-
-       chg_vc_kbd_lock(kbd, value);
-}
-
-static void k_slock(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       k_shift(vc, value, up_flag);
-       if (up_flag || rep)
-               return;
-
-       chg_vc_kbd_slock(kbd, value);
-       /* try to make Alt, oops, AltGr and such work */
-       if (!key_maps[kbd->lockstate ^ kbd->slockstate]) {
-               kbd->slockstate = 0;
-               chg_vc_kbd_slock(kbd, value);
-       }
-}
-
-/* by default, 300ms interval for combination release */
-static unsigned brl_timeout = 300;
-MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)");
-module_param(brl_timeout, uint, 0644);
-
-static unsigned brl_nbchords = 1;
-MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)");
-module_param(brl_nbchords, uint, 0644);
-
-static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag)
-{
-       static unsigned long chords;
-       static unsigned committed;
-
-       if (!brl_nbchords)
-               k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag);
-       else {
-               committed |= pattern;
-               chords++;
-               if (chords == brl_nbchords) {
-                       k_unicode(vc, BRL_UC_ROW | committed, up_flag);
-                       chords = 0;
-                       committed = 0;
-               }
-       }
-}
-
-static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       static unsigned pressed, committing;
-       static unsigned long releasestart;
-
-       if (kbd->kbdmode != VC_UNICODE) {
-               if (!up_flag)
-                       pr_warning("keyboard mode must be unicode for braille patterns\n");
-               return;
-       }
-
-       if (!value) {
-               k_unicode(vc, BRL_UC_ROW, up_flag);
-               return;
-       }
-
-       if (value > 8)
-               return;
-
-       if (!up_flag) {
-               pressed |= 1 << (value - 1);
-               if (!brl_timeout)
-                       committing = pressed;
-       } else if (brl_timeout) {
-               if (!committing ||
-                   time_after(jiffies,
-                              releasestart + msecs_to_jiffies(brl_timeout))) {
-                       committing = pressed;
-                       releasestart = jiffies;
-               }
-               pressed &= ~(1 << (value - 1));
-               if (!pressed && committing) {
-                       k_brlcommit(vc, committing, 0);
-                       committing = 0;
-               }
-       } else {
-               if (committing) {
-                       k_brlcommit(vc, committing, 0);
-                       committing = 0;
-               }
-               pressed &= ~(1 << (value - 1));
-       }
-}
-
-/*
- * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
- * or (ii) whatever pattern of lights people want to show using KDSETLED,
- * or (iii) specified bits of specified words in kernel memory.
- */
-unsigned char getledstate(void)
-{
-       return ledstate;
-}
-
-void setledstate(struct kbd_struct *kbd, unsigned int led)
-{
-       if (!(led & ~7)) {
-               ledioctl = led;
-               kbd->ledmode = LED_SHOW_IOCTL;
-       } else
-               kbd->ledmode = LED_SHOW_FLAGS;
-
-       set_leds();
-}
-
-static inline unsigned char getleds(void)
-{
-       struct kbd_struct *kbd = kbd_table + fg_console;
-       unsigned char leds;
-       int i;
-
-       if (kbd->ledmode == LED_SHOW_IOCTL)
-               return ledioctl;
-
-       leds = kbd->ledflagstate;
-
-       if (kbd->ledmode == LED_SHOW_MEM) {
-               for (i = 0; i < 3; i++)
-                       if (ledptrs[i].valid) {
-                               if (*ledptrs[i].addr & ledptrs[i].mask)
-                                       leds |= (1 << i);
-                               else
-                                       leds &= ~(1 << i);
-                       }
-       }
-       return leds;
-}
-
-static int kbd_update_leds_helper(struct input_handle *handle, void *data)
-{
-       unsigned char leds = *(unsigned char *)data;
-
-       if (test_bit(EV_LED, handle->dev->evbit)) {
-               input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
-               input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));
-               input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));
-               input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
-       }
-
-       return 0;
-}
-
-/*
- * This is the tasklet that updates LED state on all keyboards
- * attached to the box. The reason we use tasklet is that we
- * need to handle the scenario when keyboard handler is not
- * registered yet but we already getting updates form VT to
- * update led state.
- */
-static void kbd_bh(unsigned long dummy)
-{
-       unsigned char leds = getleds();
-
-       if (leds != ledstate) {
-               input_handler_for_each_handle(&kbd_handler, &leds,
-                                             kbd_update_leds_helper);
-               ledstate = leds;
-       }
-}
-
-DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
-
-#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
-    defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
-    defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
-    (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ||\
-    defined(CONFIG_AVR32)
-
-#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
-                       ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
-
-static const unsigned short x86_keycodes[256] =
-       { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
-        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-        32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-        48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-        64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
-        80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92,
-       284,285,309,  0,312, 91,327,328,329,331,333,335,336,337,338,339,
-       367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349,
-       360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355,
-       103,104,105,275,287,279,258,106,274,107,294,364,358,363,362,361,
-       291,108,381,281,290,272,292,305,280, 99,112,257,306,359,113,114,
-       264,117,271,374,379,265,266, 93, 94, 95, 85,259,375,260, 90,116,
-       377,109,111,277,278,282,283,295,296,297,299,300,301,293,303,307,
-       308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330,
-       332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 };
-
-#ifdef CONFIG_SPARC
-static int sparc_l1_a_state;
-extern void sun_do_break(void);
-#endif
-
-static int emulate_raw(struct vc_data *vc, unsigned int keycode,
-                      unsigned char up_flag)
-{
-       int code;
-
-       switch (keycode) {
-
-       case KEY_PAUSE:
-               put_queue(vc, 0xe1);
-               put_queue(vc, 0x1d | up_flag);
-               put_queue(vc, 0x45 | up_flag);
-               break;
-
-       case KEY_HANGEUL:
-               if (!up_flag)
-                       put_queue(vc, 0xf2);
-               break;
-
-       case KEY_HANJA:
-               if (!up_flag)
-                       put_queue(vc, 0xf1);
-               break;
-
-       case KEY_SYSRQ:
-               /*
-                * Real AT keyboards (that's what we're trying
-                * to emulate here emit 0xe0 0x2a 0xe0 0x37 when
-                * pressing PrtSc/SysRq alone, but simply 0x54
-                * when pressing Alt+PrtSc/SysRq.
-                */
-               if (test_bit(KEY_LEFTALT, key_down) ||
-                   test_bit(KEY_RIGHTALT, key_down)) {
-                       put_queue(vc, 0x54 | up_flag);
-               } else {
-                       put_queue(vc, 0xe0);
-                       put_queue(vc, 0x2a | up_flag);
-                       put_queue(vc, 0xe0);
-                       put_queue(vc, 0x37 | up_flag);
-               }
-               break;
-
-       default:
-               if (keycode > 255)
-                       return -1;
-
-               code = x86_keycodes[keycode];
-               if (!code)
-                       return -1;
-
-               if (code & 0x100)
-                       put_queue(vc, 0xe0);
-               put_queue(vc, (code & 0x7f) | up_flag);
-
-               break;
-       }
-
-       return 0;
-}
-
-#else
-
-#define HW_RAW(dev)    0
-
-static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag)
-{
-       if (keycode > 127)
-               return -1;
-
-       put_queue(vc, keycode | up_flag);
-       return 0;
-}
-#endif
-
-static void kbd_rawcode(unsigned char data)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-
-       kbd = kbd_table + vc->vc_num;
-       if (kbd->kbdmode == VC_RAW)
-               put_queue(vc, data);
-}
-
-static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-       unsigned short keysym, *key_map;
-       unsigned char type;
-       bool raw_mode;
-       struct tty_struct *tty;
-       int shift_final;
-       struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
-       int rc;
-
-       tty = vc->port.tty;
-
-       if (tty && (!tty->driver_data)) {
-               /* No driver data? Strange. Okay we fix it then. */
-               tty->driver_data = vc;
-       }
-
-       kbd = kbd_table + vc->vc_num;
-
-#ifdef CONFIG_SPARC
-       if (keycode == KEY_STOP)
-               sparc_l1_a_state = down;
-#endif
-
-       rep = (down == 2);
-
-       raw_mode = (kbd->kbdmode == VC_RAW);
-       if (raw_mode && !hw_raw)
-               if (emulate_raw(vc, keycode, !down << 7))
-                       if (keycode < BTN_MISC && printk_ratelimit())
-                               pr_warning("can't emulate rawmode for keycode %d\n",
-                                          keycode);
-
-#ifdef CONFIG_SPARC
-       if (keycode == KEY_A && sparc_l1_a_state) {
-               sparc_l1_a_state = false;
-               sun_do_break();
-       }
-#endif
-
-       if (kbd->kbdmode == VC_MEDIUMRAW) {
-               /*
-                * This is extended medium raw mode, with keys above 127
-                * encoded as 0, high 7 bits, low 7 bits, with the 0 bearing
-                * the 'up' flag if needed. 0 is reserved, so this shouldn't
-                * interfere with anything else. The two bytes after 0 will
-                * always have the up flag set not to interfere with older
-                * applications. This allows for 16384 different keycodes,
-                * which should be enough.
-                */
-               if (keycode < 128) {
-                       put_queue(vc, keycode | (!down << 7));
-               } else {
-                       put_queue(vc, !down << 7);
-                       put_queue(vc, (keycode >> 7) | 0x80);
-                       put_queue(vc, keycode | 0x80);
-               }
-               raw_mode = true;
-       }
-
-       if (down)
-               set_bit(keycode, key_down);
-       else
-               clear_bit(keycode, key_down);
-
-       if (rep &&
-           (!vc_kbd_mode(kbd, VC_REPEAT) ||
-            (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) {
-               /*
-                * Don't repeat a key if the input buffers are not empty and the
-                * characters get aren't echoed locally. This makes key repeat
-                * usable with slow applications and under heavy loads.
-                */
-               return;
-       }
-
-       param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
-       param.ledstate = kbd->ledflagstate;
-       key_map = key_maps[shift_final];
-
-       rc = atomic_notifier_call_chain(&keyboard_notifier_list,
-                                       KBD_KEYCODE, &param);
-       if (rc == NOTIFY_STOP || !key_map) {
-               atomic_notifier_call_chain(&keyboard_notifier_list,
-                                          KBD_UNBOUND_KEYCODE, &param);
-               compute_shiftstate();
-               kbd->slockstate = 0;
-               return;
-       }
-
-       if (keycode < NR_KEYS)
-               keysym = key_map[keycode];
-       else if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8)
-               keysym = U(K(KT_BRL, keycode - KEY_BRL_DOT1 + 1));
-       else
-               return;
-
-       type = KTYP(keysym);
-
-       if (type < 0xf0) {
-               param.value = keysym;
-               rc = atomic_notifier_call_chain(&keyboard_notifier_list,
-                                               KBD_UNICODE, &param);
-               if (rc != NOTIFY_STOP)
-                       if (down && !raw_mode)
-                               to_utf8(vc, keysym);
-               return;
-       }
-
-       type -= 0xf0;
-
-       if (type == KT_LETTER) {
-               type = KT_LATIN;
-               if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
-                       key_map = key_maps[shift_final ^ (1 << KG_SHIFT)];
-                       if (key_map)
-                               keysym = key_map[keycode];
-               }
-       }
-
-       param.value = keysym;
-       rc = atomic_notifier_call_chain(&keyboard_notifier_list,
-                                       KBD_KEYSYM, &param);
-       if (rc == NOTIFY_STOP)
-               return;
-
-       if (raw_mode && type != KT_SPEC && type != KT_SHIFT)
-               return;
-
-       (*k_handler[type])(vc, keysym & 0xff, !down);
-
-       param.ledstate = kbd->ledflagstate;
-       atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, &param);
-
-       if (type != KT_SLOCK)
-               kbd->slockstate = 0;
-}
-
-static void kbd_event(struct input_handle *handle, unsigned int event_type,
-                     unsigned int event_code, int value)
-{
-       /* We are called with interrupts disabled, just take the lock */
-       spin_lock(&kbd_event_lock);
-
-       if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
-               kbd_rawcode(value);
-       if (event_type == EV_KEY)
-               kbd_keycode(event_code, value, HW_RAW(handle->dev));
-
-       spin_unlock(&kbd_event_lock);
-
-       tasklet_schedule(&keyboard_tasklet);
-       do_poke_blanked_console = 1;
-       schedule_console_callback();
-}
-
-static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
-{
-       int i;
-
-       if (test_bit(EV_SND, dev->evbit))
-               return true;
-
-       if (test_bit(EV_KEY, dev->evbit)) {
-               for (i = KEY_RESERVED; i < BTN_MISC; i++)
-                       if (test_bit(i, dev->keybit))
-                               return true;
-               for (i = KEY_BRL_DOT1; i <= KEY_BRL_DOT10; i++)
-                       if (test_bit(i, dev->keybit))
-                               return true;
-       }
-
-       return false;
-}
-
-/*
- * When a keyboard (or other input device) is found, the kbd_connect
- * function is called. The function then looks at the device, and if it
- * likes it, it can open it and get events from it. In this (kbd_connect)
- * function, we should decide which VT to bind that keyboard to initially.
- */
-static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
-                       const struct input_device_id *id)
-{
-       struct input_handle *handle;
-       int error;
-
-       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
-       if (!handle)
-               return -ENOMEM;
-
-       handle->dev = dev;
-       handle->handler = handler;
-       handle->name = "kbd";
-
-       error = input_register_handle(handle);
-       if (error)
-               goto err_free_handle;
-
-       error = input_open_device(handle);
-       if (error)
-               goto err_unregister_handle;
-
-       return 0;
-
- err_unregister_handle:
-       input_unregister_handle(handle);
- err_free_handle:
-       kfree(handle);
-       return error;
-}
-
-static void kbd_disconnect(struct input_handle *handle)
-{
-       input_close_device(handle);
-       input_unregister_handle(handle);
-       kfree(handle);
-}
-
-/*
- * Start keyboard handler on the new keyboard by refreshing LED state to
- * match the rest of the system.
- */
-static void kbd_start(struct input_handle *handle)
-{
-       tasklet_disable(&keyboard_tasklet);
-
-       if (ledstate != 0xff)
-               kbd_update_leds_helper(handle, &ledstate);
-
-       tasklet_enable(&keyboard_tasklet);
-}
-
-static const struct input_device_id kbd_ids[] = {
-       {
-                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-                .evbit = { BIT_MASK(EV_KEY) },
-        },
-
-       {
-                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-                .evbit = { BIT_MASK(EV_SND) },
-        },
-
-       { },    /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(input, kbd_ids);
-
-static struct input_handler kbd_handler = {
-       .event          = kbd_event,
-       .match          = kbd_match,
-       .connect        = kbd_connect,
-       .disconnect     = kbd_disconnect,
-       .start          = kbd_start,
-       .name           = "kbd",
-       .id_table       = kbd_ids,
-};
-
-int __init kbd_init(void)
-{
-       int i;
-       int error;
-
-        for (i = 0; i < MAX_NR_CONSOLES; i++) {
-               kbd_table[i].ledflagstate = KBD_DEFLEDS;
-               kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
-               kbd_table[i].ledmode = LED_SHOW_FLAGS;
-               kbd_table[i].lockstate = KBD_DEFLOCK;
-               kbd_table[i].slockstate = 0;
-               kbd_table[i].modeflags = KBD_DEFMODE;
-               kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
-       }
-
-       error = input_register_handler(&kbd_handler);
-       if (error)
-               return error;
-
-       tasklet_enable(&keyboard_tasklet);
-       tasklet_schedule(&keyboard_tasklet);
-
-       return 0;
-}
diff --git a/drivers/char/n_gsm.c b/drivers/char/n_gsm.c
deleted file mode 100644 (file)
index 04ef3ef..0000000
+++ /dev/null
@@ -1,2763 +0,0 @@
-/*
- * n_gsm.c GSM 0710 tty multiplexor
- * Copyright (c) 2009/10 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *     * THIS IS A DEVELOPMENT SNAPSHOT IT IS NOT A FINAL RELEASE *
- *
- * TO DO:
- *     Mostly done:    ioctls for setting modes/timing
- *     Partly done:    hooks so you can pull off frames to non tty devs
- *     Restart DLCI 0 when it closes ?
- *     Test basic encoding
- *     Improve the tx engine
- *     Resolve tx side locking by adding a queue_head and routing
- *             all control traffic via it
- *     General tidy/document
- *     Review the locking/move to refcounts more (mux now moved to an
- *             alloc/free model ready)
- *     Use newest tty open/close port helpers and install hooks
- *     What to do about power functions ?
- *     Termios setting and negotiation
- *     Do we need a 'which mux are you' ioctl to correlate mux and tty sets
- *
- */
-
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/ctype.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <linux/file.h>
-#include <linux/uaccess.h>
-#include <linux/module.h>
-#include <linux/timer.h>
-#include <linux/tty_flip.h>
-#include <linux/tty_driver.h>
-#include <linux/serial.h>
-#include <linux/kfifo.h>
-#include <linux/skbuff.h>
-#include <linux/gsmmux.h>
-
-static int debug;
-module_param(debug, int, 0600);
-
-#define T1     (HZ/10)
-#define T2     (HZ/3)
-#define N2     3
-
-/* Use long timers for testing at low speed with debug on */
-#ifdef DEBUG_TIMING
-#define T1     HZ
-#define T2     (2 * HZ)
-#endif
-
-/* Semi-arbitary buffer size limits. 0710 is normally run with 32-64 byte
-   limits so this is plenty */
-#define MAX_MRU 512
-#define MAX_MTU 512
-
-/*
- *     Each block of data we have queued to go out is in the form of
- *     a gsm_msg which holds everything we need in a link layer independant
- *     format
- */
-
-struct gsm_msg {
-       struct gsm_msg *next;
-       u8 addr;                /* DLCI address + flags */
-       u8 ctrl;                /* Control byte + flags */
-       unsigned int len;       /* Length of data block (can be zero) */
-       unsigned char *data;    /* Points into buffer but not at the start */
-       unsigned char buffer[0];
-};
-
-/*
- *     Each active data link has a gsm_dlci structure associated which ties
- *     the link layer to an optional tty (if the tty side is open). To avoid
- *     complexity right now these are only ever freed up when the mux is
- *     shut down.
- *
- *     At the moment we don't free DLCI objects until the mux is torn down
- *     this avoid object life time issues but might be worth review later.
- */
-
-struct gsm_dlci {
-       struct gsm_mux *gsm;
-       int addr;
-       int state;
-#define DLCI_CLOSED            0
-#define DLCI_OPENING           1       /* Sending SABM not seen UA */
-#define DLCI_OPEN              2       /* SABM/UA complete */
-#define DLCI_CLOSING           3       /* Sending DISC not seen UA/DM */
-
-       /* Link layer */
-       spinlock_t lock;        /* Protects the internal state */
-       struct timer_list t1;   /* Retransmit timer for SABM and UA */
-       int retries;
-       /* Uplink tty if active */
-       struct tty_port port;   /* The tty bound to this DLCI if there is one */
-       struct kfifo *fifo;     /* Queue fifo for the DLCI */
-       struct kfifo _fifo;     /* For new fifo API porting only */
-       int adaption;           /* Adaption layer in use */
-       u32 modem_rx;           /* Our incoming virtual modem lines */
-       u32 modem_tx;           /* Our outgoing modem lines */
-       int dead;               /* Refuse re-open */
-       /* Flow control */
-       int throttled;          /* Private copy of throttle state */
-       int constipated;        /* Throttle status for outgoing */
-       /* Packetised I/O */
-       struct sk_buff *skb;    /* Frame being sent */
-       struct sk_buff_head skb_list;   /* Queued frames */
-       /* Data handling callback */
-       void (*data)(struct gsm_dlci *dlci, u8 *data, int len);
-};
-
-/* DLCI 0, 62/63 are special or reseved see gsmtty_open */
-
-#define NUM_DLCI               64
-
-/*
- *     DLCI 0 is used to pass control blocks out of band of the data
- *     flow (and with a higher link priority). One command can be outstanding
- *     at a time and we use this structure to manage them. They are created
- *     and destroyed by the user context, and updated by the receive paths
- *     and timers
- */
-
-struct gsm_control {
-       u8 cmd;         /* Command we are issuing */
-       u8 *data;       /* Data for the command in case we retransmit */
-       int len;        /* Length of block for retransmission */
-       int done;       /* Done flag */
-       int error;      /* Error if any */
-};
-
-/*
- *     Each GSM mux we have is represented by this structure. If we are
- *     operating as an ldisc then we use this structure as our ldisc
- *     state. We need to sort out lifetimes and locking with respect
- *     to the gsm mux array. For now we don't free DLCI objects that
- *     have been instantiated until the mux itself is terminated.
- *
- *     To consider further: tty open versus mux shutdown.
- */
-
-struct gsm_mux {
-       struct tty_struct *tty;         /* The tty our ldisc is bound to */
-       spinlock_t lock;
-
-       /* Events on the GSM channel */
-       wait_queue_head_t event;
-
-       /* Bits for GSM mode decoding */
-
-       /* Framing Layer */
-       unsigned char *buf;
-       int state;
-#define GSM_SEARCH             0
-#define GSM_START              1
-#define GSM_ADDRESS            2
-#define GSM_CONTROL            3
-#define GSM_LEN                        4
-#define GSM_DATA               5
-#define GSM_FCS                        6
-#define GSM_OVERRUN            7
-       unsigned int len;
-       unsigned int address;
-       unsigned int count;
-       int escape;
-       int encoding;
-       u8 control;
-       u8 fcs;
-       u8 *txframe;                    /* TX framing buffer */
-
-       /* Methods for the receiver side */
-       void (*receive)(struct gsm_mux *gsm, u8 ch);
-       void (*error)(struct gsm_mux *gsm, u8 ch, u8 flag);
-       /* And transmit side */
-       int (*output)(struct gsm_mux *mux, u8 *data, int len);
-
-       /* Link Layer */
-       unsigned int mru;
-       unsigned int mtu;
-       int initiator;                  /* Did we initiate connection */
-       int dead;                       /* Has the mux been shut down */
-       struct gsm_dlci *dlci[NUM_DLCI];
-       int constipated;                /* Asked by remote to shut up */
-
-       spinlock_t tx_lock;
-       unsigned int tx_bytes;          /* TX data outstanding */
-#define TX_THRESH_HI           8192
-#define TX_THRESH_LO           2048
-       struct gsm_msg *tx_head;        /* Pending data packets */
-       struct gsm_msg *tx_tail;
-
-       /* Control messages */
-       struct timer_list t2_timer;     /* Retransmit timer for commands */
-       int cretries;                   /* Command retry counter */
-       struct gsm_control *pending_cmd;/* Our current pending command */
-       spinlock_t control_lock;        /* Protects the pending command */
-
-       /* Configuration */
-       int adaption;           /* 1 or 2 supported */
-       u8 ftype;               /* UI or UIH */
-       int t1, t2;             /* Timers in 1/100th of a sec */
-       int n2;                 /* Retry count */
-
-       /* Statistics (not currently exposed) */
-       unsigned long bad_fcs;
-       unsigned long malformed;
-       unsigned long io_error;
-       unsigned long bad_size;
-       unsigned long unsupported;
-};
-
-
-/*
- *     Mux objects - needed so that we can translate a tty index into the
- *     relevant mux and DLCI.
- */
-
-#define MAX_MUX                4                       /* 256 minors */
-static struct gsm_mux *gsm_mux[MAX_MUX];       /* GSM muxes */
-static spinlock_t gsm_mux_lock;
-
-/*
- *     This section of the driver logic implements the GSM encodings
- *     both the basic and the 'advanced'. Reliable transport is not
- *     supported.
- */
-
-#define CR                     0x02
-#define EA                     0x01
-#define        PF                      0x10
-
-/* I is special: the rest are ..*/
-#define RR                     0x01
-#define UI                     0x03
-#define RNR                    0x05
-#define REJ                    0x09
-#define DM                     0x0F
-#define SABM                   0x2F
-#define DISC                   0x43
-#define UA                     0x63
-#define        UIH                     0xEF
-
-/* Channel commands */
-#define CMD_NSC                        0x09
-#define CMD_TEST               0x11
-#define CMD_PSC                        0x21
-#define CMD_RLS                        0x29
-#define CMD_FCOFF              0x31
-#define CMD_PN                 0x41
-#define CMD_RPN                        0x49
-#define CMD_FCON               0x51
-#define CMD_CLD                        0x61
-#define CMD_SNC                        0x69
-#define CMD_MSC                        0x71
-
-/* Virtual modem bits */
-#define MDM_FC                 0x01
-#define MDM_RTC                        0x02
-#define MDM_RTR                        0x04
-#define MDM_IC                 0x20
-#define MDM_DV                 0x40
-
-#define GSM0_SOF               0xF9
-#define GSM1_SOF               0x7E
-#define GSM1_ESCAPE            0x7D
-#define GSM1_ESCAPE_BITS       0x20
-#define XON                    0x11
-#define XOFF                   0x13
-
-static const struct tty_port_operations gsm_port_ops;
-
-/*
- *     CRC table for GSM 0710
- */
-
-static const u8 gsm_fcs8[256] = {
-       0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75,
-       0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
-       0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69,
-       0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
-       0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D,
-       0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
-       0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51,
-       0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
-       0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05,
-       0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
-       0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19,
-       0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
-       0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D,
-       0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
-       0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21,
-       0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
-       0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95,
-       0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
-       0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89,
-       0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
-       0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD,
-       0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
-       0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1,
-       0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
-       0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5,
-       0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
-       0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9,
-       0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
-       0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD,
-       0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
-       0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1,
-       0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
-};
-
-#define INIT_FCS       0xFF
-#define GOOD_FCS       0xCF
-
-/**
- *     gsm_fcs_add     -       update FCS
- *     @fcs: Current FCS
- *     @c: Next data
- *
- *     Update the FCS to include c. Uses the algorithm in the specification
- *     notes.
- */
-
-static inline u8 gsm_fcs_add(u8 fcs, u8 c)
-{
-       return gsm_fcs8[fcs ^ c];
-}
-
-/**
- *     gsm_fcs_add_block       -       update FCS for a block
- *     @fcs: Current FCS
- *     @c: buffer of data
- *     @len: length of buffer
- *
- *     Update the FCS to include c. Uses the algorithm in the specification
- *     notes.
- */
-
-static inline u8 gsm_fcs_add_block(u8 fcs, u8 *c, int len)
-{
-       while (len--)
-               fcs = gsm_fcs8[fcs ^ *c++];
-       return fcs;
-}
-
-/**
- *     gsm_read_ea             -       read a byte into an EA
- *     @val: variable holding value
- *     c: byte going into the EA
- *
- *     Processes one byte of an EA. Updates the passed variable
- *     and returns 1 if the EA is now completely read
- */
-
-static int gsm_read_ea(unsigned int *val, u8 c)
-{
-       /* Add the next 7 bits into the value */
-       *val <<= 7;
-       *val |= c >> 1;
-       /* Was this the last byte of the EA 1 = yes*/
-       return c & EA;
-}
-
-/**
- *     gsm_encode_modem        -       encode modem data bits
- *     @dlci: DLCI to encode from
- *
- *     Returns the correct GSM encoded modem status bits (6 bit field) for
- *     the current status of the DLCI and attached tty object
- */
-
-static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
-{
-       u8 modembits = 0;
-       /* FC is true flow control not modem bits */
-       if (dlci->throttled)
-               modembits |= MDM_FC;
-       if (dlci->modem_tx & TIOCM_DTR)
-               modembits |= MDM_RTC;
-       if (dlci->modem_tx & TIOCM_RTS)
-               modembits |= MDM_RTR;
-       if (dlci->modem_tx & TIOCM_RI)
-               modembits |= MDM_IC;
-       if (dlci->modem_tx & TIOCM_CD)
-               modembits |= MDM_DV;
-       return modembits;
-}
-
-/**
- *     gsm_print_packet        -       display a frame for debug
- *     @hdr: header to print before decode
- *     @addr: address EA from the frame
- *     @cr: C/R bit from the frame
- *     @control: control including PF bit
- *     @data: following data bytes
- *     @dlen: length of data
- *
- *     Displays a packet in human readable format for debugging purposes. The
- *     style is based on amateur radio LAP-B dump display.
- */
-
-static void gsm_print_packet(const char *hdr, int addr, int cr,
-                                       u8 control, const u8 *data, int dlen)
-{
-       if (!(debug & 1))
-               return;
-
-       printk(KERN_INFO "%s %d) %c: ", hdr, addr, "RC"[cr]);
-
-       switch (control & ~PF) {
-       case SABM:
-               printk(KERN_CONT "SABM");
-               break;
-       case UA:
-               printk(KERN_CONT "UA");
-               break;
-       case DISC:
-               printk(KERN_CONT "DISC");
-               break;
-       case DM:
-               printk(KERN_CONT "DM");
-               break;
-       case UI:
-               printk(KERN_CONT "UI");
-               break;
-       case UIH:
-               printk(KERN_CONT "UIH");
-               break;
-       default:
-               if (!(control & 0x01)) {
-                       printk(KERN_CONT "I N(S)%d N(R)%d",
-                               (control & 0x0E) >> 1, (control & 0xE)>> 5);
-               } else switch (control & 0x0F) {
-               case RR:
-                       printk("RR(%d)", (control & 0xE0) >> 5);
-                       break;
-               case RNR:
-                       printk("RNR(%d)", (control & 0xE0) >> 5);
-                       break;
-               case REJ:
-                       printk("REJ(%d)", (control & 0xE0) >> 5);
-                       break;
-               default:
-                       printk(KERN_CONT "[%02X]", control);
-               }
-       }
-
-       if (control & PF)
-               printk(KERN_CONT "(P)");
-       else
-               printk(KERN_CONT "(F)");
-
-       if (dlen) {
-               int ct = 0;
-               while (dlen--) {
-                       if (ct % 8 == 0)
-                               printk(KERN_CONT "\n    ");
-                       printk(KERN_CONT "%02X ", *data++);
-                       ct++;
-               }
-       }
-       printk(KERN_CONT "\n");
-}
-
-
-/*
- *     Link level transmission side
- */
-
-/**
- *     gsm_stuff_packet        -       bytestuff a packet
- *     @ibuf: input
- *     @obuf: output
- *     @len: length of input
- *
- *     Expand a buffer by bytestuffing it. The worst case size change
- *     is doubling and the caller is responsible for handing out
- *     suitable sized buffers.
- */
-
-static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
-{
-       int olen = 0;
-       while (len--) {
-               if (*input == GSM1_SOF || *input == GSM1_ESCAPE
-                   || *input == XON || *input == XOFF) {
-                       *output++ = GSM1_ESCAPE;
-                       *output++ = *input++ ^ GSM1_ESCAPE_BITS;
-                       olen++;
-               } else
-                       *output++ = *input++;
-               olen++;
-       }
-       return olen;
-}
-
-static void hex_packet(const unsigned char *p, int len)
-{
-       int i;
-       for (i = 0; i < len; i++) {
-               if (i && (i % 16) == 0)
-                       printk("\n");
-               printk("%02X ", *p++);
-       }
-       printk("\n");
-}
-
-/**
- *     gsm_send        -       send a control frame
- *     @gsm: our GSM mux
- *     @addr: address for control frame
- *     @cr: command/response bit
- *     @control:  control byte including PF bit
- *
- *     Format up and transmit a control frame. These do not go via the
- *     queueing logic as they should be transmitted ahead of data when
- *     they are needed.
- *
- *     FIXME: Lock versus data TX path
- */
-
-static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
-{
-       int len;
-       u8 cbuf[10];
-       u8 ibuf[3];
-
-       switch (gsm->encoding) {
-       case 0:
-               cbuf[0] = GSM0_SOF;
-               cbuf[1] = (addr << 2) | (cr << 1) | EA;
-               cbuf[2] = control;
-               cbuf[3] = EA;   /* Length of data = 0 */
-               cbuf[4] = 0xFF - gsm_fcs_add_block(INIT_FCS, cbuf + 1, 3);
-               cbuf[5] = GSM0_SOF;
-               len = 6;
-               break;
-       case 1:
-       case 2:
-               /* Control frame + packing (but not frame stuffing) in mode 1 */
-               ibuf[0] = (addr << 2) | (cr << 1) | EA;
-               ibuf[1] = control;
-               ibuf[2] = 0xFF - gsm_fcs_add_block(INIT_FCS, ibuf, 2);
-               /* Stuffing may double the size worst case */
-               len = gsm_stuff_frame(ibuf, cbuf + 1, 3);
-               /* Now add the SOF markers */
-               cbuf[0] = GSM1_SOF;
-               cbuf[len + 1] = GSM1_SOF;
-               /* FIXME: we can omit the lead one in many cases */
-               len += 2;
-               break;
-       default:
-               WARN_ON(1);
-               return;
-       }
-       gsm->output(gsm, cbuf, len);
-       gsm_print_packet("-->", addr, cr, control, NULL, 0);
-}
-
-/**
- *     gsm_response    -       send a control response
- *     @gsm: our GSM mux
- *     @addr: address for control frame
- *     @control:  control byte including PF bit
- *
- *     Format up and transmit a link level response frame.
- */
-
-static inline void gsm_response(struct gsm_mux *gsm, int addr, int control)
-{
-       gsm_send(gsm, addr, 0, control);
-}
-
-/**
- *     gsm_command     -       send a control command
- *     @gsm: our GSM mux
- *     @addr: address for control frame
- *     @control:  control byte including PF bit
- *
- *     Format up and transmit a link level command frame.
- */
-
-static inline void gsm_command(struct gsm_mux *gsm, int addr, int control)
-{
-       gsm_send(gsm, addr, 1, control);
-}
-
-/* Data transmission */
-
-#define HDR_LEN                6       /* ADDR CTRL [LEN.2] DATA FCS */
-
-/**
- *     gsm_data_alloc          -       allocate data frame
- *     @gsm: GSM mux
- *     @addr: DLCI address
- *     @len: length excluding header and FCS
- *     @ctrl: control byte
- *
- *     Allocate a new data buffer for sending frames with data. Space is left
- *     at the front for header bytes but that is treated as an implementation
- *     detail and not for the high level code to use
- */
-
-static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
-                                                               u8 ctrl)
-{
-       struct gsm_msg *m = kmalloc(sizeof(struct gsm_msg) + len + HDR_LEN,
-                                                               GFP_ATOMIC);
-       if (m == NULL)
-               return NULL;
-       m->data = m->buffer + HDR_LEN - 1;      /* Allow for FCS */
-       m->len = len;
-       m->addr = addr;
-       m->ctrl = ctrl;
-       m->next = NULL;
-       return m;
-}
-
-/**
- *     gsm_data_kick           -       poke the queue
- *     @gsm: GSM Mux
- *
- *     The tty device has called us to indicate that room has appeared in
- *     the transmit queue. Ram more data into the pipe if we have any
- *
- *     FIXME: lock against link layer control transmissions
- */
-
-static void gsm_data_kick(struct gsm_mux *gsm)
-{
-       struct gsm_msg *msg = gsm->tx_head;
-       int len;
-       int skip_sof = 0;
-
-       /* FIXME: We need to apply this solely to data messages */
-       if (gsm->constipated)
-               return;
-
-       while (gsm->tx_head != NULL) {
-               msg = gsm->tx_head;
-               if (gsm->encoding != 0) {
-                       gsm->txframe[0] = GSM1_SOF;
-                       len = gsm_stuff_frame(msg->data,
-                                               gsm->txframe + 1, msg->len);
-                       gsm->txframe[len + 1] = GSM1_SOF;
-                       len += 2;
-               } else {
-                       gsm->txframe[0] = GSM0_SOF;
-                       memcpy(gsm->txframe + 1 , msg->data, msg->len);
-                       gsm->txframe[msg->len + 1] = GSM0_SOF;
-                       len = msg->len + 2;
-               }
-
-               if (debug & 4) {
-                       printk("gsm_data_kick: \n");
-                       hex_packet(gsm->txframe, len);
-               }
-
-               if (gsm->output(gsm, gsm->txframe + skip_sof,
-                                               len - skip_sof) < 0)
-                       break;
-               /* FIXME: Can eliminate one SOF in many more cases */
-               gsm->tx_head = msg->next;
-               if (gsm->tx_head == NULL)
-                       gsm->tx_tail = NULL;
-               gsm->tx_bytes -= msg->len;
-               kfree(msg);
-               /* For a burst of frames skip the extra SOF within the
-                  burst */
-               skip_sof = 1;
-       }
-}
-
-/**
- *     __gsm_data_queue                -       queue a UI or UIH frame
- *     @dlci: DLCI sending the data
- *     @msg: message queued
- *
- *     Add data to the transmit queue and try and get stuff moving
- *     out of the mux tty if not already doing so. The Caller must hold
- *     the gsm tx lock.
- */
-
-static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
-{
-       struct gsm_mux *gsm = dlci->gsm;
-       u8 *dp = msg->data;
-       u8 *fcs = dp + msg->len;
-
-       /* Fill in the header */
-       if (gsm->encoding == 0) {
-               if (msg->len < 128)
-                       *--dp = (msg->len << 1) | EA;
-               else {
-                       *--dp = (msg->len >> 6) | EA;
-                       *--dp = (msg->len & 127) << 1;
-               }
-       }
-
-       *--dp = msg->ctrl;
-       if (gsm->initiator)
-               *--dp = (msg->addr << 2) | 2 | EA;
-       else
-               *--dp = (msg->addr << 2) | EA;
-       *fcs = gsm_fcs_add_block(INIT_FCS, dp , msg->data - dp);
-       /* Ugly protocol layering violation */
-       if (msg->ctrl == UI || msg->ctrl == (UI|PF))
-               *fcs = gsm_fcs_add_block(*fcs, msg->data, msg->len);
-       *fcs = 0xFF - *fcs;
-
-       gsm_print_packet("Q> ", msg->addr, gsm->initiator, msg->ctrl,
-                                                       msg->data, msg->len);
-
-       /* Move the header back and adjust the length, also allow for the FCS
-          now tacked on the end */
-       msg->len += (msg->data - dp) + 1;
-       msg->data = dp;
-
-       /* Add to the actual output queue */
-       if (gsm->tx_tail)
-               gsm->tx_tail->next = msg;
-       else
-               gsm->tx_head = msg;
-       gsm->tx_tail = msg;
-       gsm->tx_bytes += msg->len;
-       gsm_data_kick(gsm);
-}
-
-/**
- *     gsm_data_queue          -       queue a UI or UIH frame
- *     @dlci: DLCI sending the data
- *     @msg: message queued
- *
- *     Add data to the transmit queue and try and get stuff moving
- *     out of the mux tty if not already doing so. Take the
- *     the gsm tx lock and dlci lock.
- */
-
-static void gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
-       __gsm_data_queue(dlci, msg);
-       spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
-}
-
-/**
- *     gsm_dlci_data_output    -       try and push data out of a DLCI
- *     @gsm: mux
- *     @dlci: the DLCI to pull data from
- *
- *     Pull data from a DLCI and send it into the transmit queue if there
- *     is data. Keep to the MRU of the mux. This path handles the usual tty
- *     interface which is a byte stream with optional modem data.
- *
- *     Caller must hold the tx_lock of the mux.
- */
-
-static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
-{
-       struct gsm_msg *msg;
-       u8 *dp;
-       int len, size;
-       int h = dlci->adaption - 1;
-
-       len = kfifo_len(dlci->fifo);
-       if (len == 0)
-               return 0;
-
-       /* MTU/MRU count only the data bits */
-       if (len > gsm->mtu)
-               len = gsm->mtu;
-
-       size = len + h;
-
-       msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
-       /* FIXME: need a timer or something to kick this so it can't
-          get stuck with no work outstanding and no buffer free */
-       if (msg == NULL)
-               return -ENOMEM;
-       dp = msg->data;
-       switch (dlci->adaption) {
-       case 1: /* Unstructured */
-               break;
-       case 2: /* Unstructed with modem bits. Always one byte as we never
-                  send inline break data */
-               *dp += gsm_encode_modem(dlci);
-               len--;
-               break;
-       }
-       WARN_ON(kfifo_out_locked(dlci->fifo, dp , len, &dlci->lock) != len);
-       __gsm_data_queue(dlci, msg);
-       /* Bytes of data we used up */
-       return size;
-}
-
-/**
- *     gsm_dlci_data_output_framed  -  try and push data out of a DLCI
- *     @gsm: mux
- *     @dlci: the DLCI to pull data from
- *
- *     Pull data from a DLCI and send it into the transmit queue if there
- *     is data. Keep to the MRU of the mux. This path handles framed data
- *     queued as skbuffs to the DLCI.
- *
- *     Caller must hold the tx_lock of the mux.
- */
-
-static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
-                                               struct gsm_dlci *dlci)
-{
-       struct gsm_msg *msg;
-       u8 *dp;
-       int len, size;
-       int last = 0, first = 0;
-       int overhead = 0;
-
-       /* One byte per frame is used for B/F flags */
-       if (dlci->adaption == 4)
-               overhead = 1;
-
-       /* dlci->skb is locked by tx_lock */
-       if (dlci->skb == NULL) {
-               dlci->skb = skb_dequeue(&dlci->skb_list);
-               if (dlci->skb == NULL)
-                       return 0;
-               first = 1;
-       }
-       len = dlci->skb->len + overhead;
-
-       /* MTU/MRU count only the data bits */
-       if (len > gsm->mtu) {
-               if (dlci->adaption == 3) {
-                       /* Over long frame, bin it */
-                       kfree_skb(dlci->skb);
-                       dlci->skb = NULL;
-                       return 0;
-               }
-               len = gsm->mtu;
-       } else
-               last = 1;
-
-       size = len + overhead;
-       msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
-
-       /* FIXME: need a timer or something to kick this so it can't
-          get stuck with no work outstanding and no buffer free */
-       if (msg == NULL)
-               return -ENOMEM;
-       dp = msg->data;
-
-       if (dlci->adaption == 4) { /* Interruptible framed (Packetised Data) */
-               /* Flag byte to carry the start/end info */
-               *dp++ = last << 7 | first << 6 | 1;     /* EA */
-               len--;
-       }
-       memcpy(dp, skb_pull(dlci->skb, len), len);
-       __gsm_data_queue(dlci, msg);
-       if (last)
-               dlci->skb = NULL;
-       return size;
-}
-
-/**
- *     gsm_dlci_data_sweep             -       look for data to send
- *     @gsm: the GSM mux
- *
- *     Sweep the GSM mux channels in priority order looking for ones with
- *     data to send. We could do with optimising this scan a bit. We aim
- *     to fill the queue totally or up to TX_THRESH_HI bytes. Once we hit
- *     TX_THRESH_LO we get called again
- *
- *     FIXME: We should round robin between groups and in theory you can
- *     renegotiate DLCI priorities with optional stuff. Needs optimising.
- */
-
-static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
-{
-       int len;
-       /* Priority ordering: We should do priority with RR of the groups */
-       int i = 1;
-
-       while (i < NUM_DLCI) {
-               struct gsm_dlci *dlci;
-
-               if (gsm->tx_bytes > TX_THRESH_HI)
-                       break;
-               dlci = gsm->dlci[i];
-               if (dlci == NULL || dlci->constipated) {
-                       i++;
-                       continue;
-               }
-               if (dlci->adaption < 3)
-                       len = gsm_dlci_data_output(gsm, dlci);
-               else
-                       len = gsm_dlci_data_output_framed(gsm, dlci);
-               if (len < 0)
-                       break;
-               /* DLCI empty - try the next */
-               if (len == 0)
-                       i++;
-       }
-}
-
-/**
- *     gsm_dlci_data_kick      -       transmit if possible
- *     @dlci: DLCI to kick
- *
- *     Transmit data from this DLCI if the queue is empty. We can't rely on
- *     a tty wakeup except when we filled the pipe so we need to fire off
- *     new data ourselves in other cases.
- */
-
-static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
-       /* If we have nothing running then we need to fire up */
-       if (dlci->gsm->tx_bytes == 0)
-               gsm_dlci_data_output(dlci->gsm, dlci);
-       else if (dlci->gsm->tx_bytes < TX_THRESH_LO)
-               gsm_dlci_data_sweep(dlci->gsm);
-       spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
-}
-
-/*
- *     Control message processing
- */
-
-
-/**
- *     gsm_control_reply       -       send a response frame to a control
- *     @gsm: gsm channel
- *     @cmd: the command to use
- *     @data: data to follow encoded info
- *     @dlen: length of data
- *
- *     Encode up and queue a UI/UIH frame containing our response.
- */
-
-static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data,
-                                       int dlen)
-{
-       struct gsm_msg *msg;
-       msg = gsm_data_alloc(gsm, 0, dlen + 2, gsm->ftype);
-       msg->data[0] = (cmd & 0xFE) << 1 | EA;  /* Clear C/R */
-       msg->data[1] = (dlen << 1) | EA;
-       memcpy(msg->data + 2, data, dlen);
-       gsm_data_queue(gsm->dlci[0], msg);
-}
-
-/**
- *     gsm_process_modem       -       process received modem status
- *     @tty: virtual tty bound to the DLCI
- *     @dlci: DLCI to affect
- *     @modem: modem bits (full EA)
- *
- *     Used when a modem control message or line state inline in adaption
- *     layer 2 is processed. Sort out the local modem state and throttles
- */
-
-static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
-                                                       u32 modem)
-{
-       int  mlines = 0;
-       u8 brk = modem >> 6;
-
-       /* Flow control/ready to communicate */
-       if (modem & MDM_FC) {
-               /* Need to throttle our output on this device */
-               dlci->constipated = 1;
-       }
-       if (modem & MDM_RTC) {
-               mlines |= TIOCM_DSR | TIOCM_DTR;
-               dlci->constipated = 0;
-               gsm_dlci_data_kick(dlci);
-       }
-       /* Map modem bits */
-       if (modem & MDM_RTR)
-               mlines |= TIOCM_RTS | TIOCM_CTS;
-       if (modem & MDM_IC)
-               mlines |= TIOCM_RI;
-       if (modem & MDM_DV)
-               mlines |= TIOCM_CD;
-
-       /* Carrier drop -> hangup */
-       if (tty) {
-               if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
-                       if (!(tty->termios->c_cflag & CLOCAL))
-                               tty_hangup(tty);
-               if (brk & 0x01)
-                       tty_insert_flip_char(tty, 0, TTY_BREAK);
-       }
-       dlci->modem_rx = mlines;
-}
-
-/**
- *     gsm_control_modem       -       modem status received
- *     @gsm: GSM channel
- *     @data: data following command
- *     @clen: command length
- *
- *     We have received a modem status control message. This is used by
- *     the GSM mux protocol to pass virtual modem line status and optionally
- *     to indicate break signals. Unpack it, convert to Linux representation
- *     and if need be stuff a break message down the tty.
- */
-
-static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
-{
-       unsigned int addr = 0;
-       unsigned int modem = 0;
-       struct gsm_dlci *dlci;
-       int len = clen;
-       u8 *dp = data;
-       struct tty_struct *tty;
-
-       while (gsm_read_ea(&addr, *dp++) == 0) {
-               len--;
-               if (len == 0)
-                       return;
-       }
-       /* Must be at least one byte following the EA */
-       len--;
-       if (len <= 0)
-               return;
-
-       addr >>= 1;
-       /* Closed port, or invalid ? */
-       if (addr == 0 || addr >= NUM_DLCI || gsm->dlci[addr] == NULL)
-               return;
-       dlci = gsm->dlci[addr];
-
-       while (gsm_read_ea(&modem, *dp++) == 0) {
-               len--;
-               if (len == 0)
-                       return;
-       }
-       tty = tty_port_tty_get(&dlci->port);
-       gsm_process_modem(tty, dlci, modem);
-       if (tty) {
-               tty_wakeup(tty);
-               tty_kref_put(tty);
-       }
-       gsm_control_reply(gsm, CMD_MSC, data, clen);
-}
-
-/**
- *     gsm_control_rls         -       remote line status
- *     @gsm: GSM channel
- *     @data: data bytes
- *     @clen: data length
- *
- *     The modem sends us a two byte message on the control channel whenever
- *     it wishes to send us an error state from the virtual link. Stuff
- *     this into the uplink tty if present
- */
-
-static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
-{
-       struct tty_struct *tty;
-       unsigned int addr = 0 ;
-       u8 bits;
-       int len = clen;
-       u8 *dp = data;
-
-       while (gsm_read_ea(&addr, *dp++) == 0) {
-               len--;
-               if (len == 0)
-                       return;
-       }
-       /* Must be at least one byte following ea */
-       len--;
-       if (len <= 0)
-               return;
-       addr >>= 1;
-       /* Closed port, or invalid ? */
-       if (addr == 0 || addr >= NUM_DLCI || gsm->dlci[addr] == NULL)
-               return;
-       /* No error ? */
-       bits = *dp;
-       if ((bits & 1) == 0)
-               return;
-       /* See if we have an uplink tty */
-       tty = tty_port_tty_get(&gsm->dlci[addr]->port);
-
-       if (tty) {
-               if (bits & 2)
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               if (bits & 4)
-                       tty_insert_flip_char(tty, 0, TTY_PARITY);
-               if (bits & 8)
-                       tty_insert_flip_char(tty, 0, TTY_FRAME);
-               tty_flip_buffer_push(tty);
-               tty_kref_put(tty);
-       }
-       gsm_control_reply(gsm, CMD_RLS, data, clen);
-}
-
-static void gsm_dlci_begin_close(struct gsm_dlci *dlci);
-
-/**
- *     gsm_control_message     -       DLCI 0 control processing
- *     @gsm: our GSM mux
- *     @command:  the command EA
- *     @data: data beyond the command/length EAs
- *     @clen: length
- *
- *     Input processor for control messages from the other end of the link.
- *     Processes the incoming request and queues a response frame or an
- *     NSC response if not supported
- */
-
-static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
-                                                       u8 *data, int clen)
-{
-       u8 buf[1];
-       switch (command) {
-       case CMD_CLD: {
-               struct gsm_dlci *dlci = gsm->dlci[0];
-               /* Modem wishes to close down */
-               if (dlci) {
-                       dlci->dead = 1;
-                       gsm->dead = 1;
-                       gsm_dlci_begin_close(dlci);
-               }
-               }
-               break;
-       case CMD_TEST:
-               /* Modem wishes to test, reply with the data */
-               gsm_control_reply(gsm, CMD_TEST, data, clen);
-               break;
-       case CMD_FCON:
-               /* Modem wants us to STFU */
-               gsm->constipated = 1;
-               gsm_control_reply(gsm, CMD_FCON, NULL, 0);
-               break;
-       case CMD_FCOFF:
-               /* Modem can accept data again */
-               gsm->constipated = 0;
-               gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
-               /* Kick the link in case it is idling */
-               gsm_data_kick(gsm);
-               break;
-       case CMD_MSC:
-               /* Out of band modem line change indicator for a DLCI */
-               gsm_control_modem(gsm, data, clen);
-               break;
-       case CMD_RLS:
-               /* Out of band error reception for a DLCI */
-               gsm_control_rls(gsm, data, clen);
-               break;
-       case CMD_PSC:
-               /* Modem wishes to enter power saving state */
-               gsm_control_reply(gsm, CMD_PSC, NULL, 0);
-               break;
-               /* Optional unsupported commands */
-       case CMD_PN:    /* Parameter negotiation */
-       case CMD_RPN:   /* Remote port negotation */
-       case CMD_SNC:   /* Service negotation command */
-       default:
-               /* Reply to bad commands with an NSC */
-               buf[0] = command;
-               gsm_control_reply(gsm, CMD_NSC, buf, 1);
-               break;
-       }
-}
-
-/**
- *     gsm_control_response    -       process a response to our control
- *     @gsm: our GSM mux
- *     @command: the command (response) EA
- *     @data: data beyond the command/length EA
- *     @clen: length
- *
- *     Process a response to an outstanding command. We only allow a single
- *     control message in flight so this is fairly easy. All the clean up
- *     is done by the caller, we just update the fields, flag it as done
- *     and return
- */
-
-static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
-                                                       u8 *data, int clen)
-{
-       struct gsm_control *ctrl;
-       unsigned long flags;
-
-       spin_lock_irqsave(&gsm->control_lock, flags);
-
-       ctrl = gsm->pending_cmd;
-       /* Does the reply match our command */
-       command |= 1;
-       if (ctrl != NULL && (command == ctrl->cmd || command == CMD_NSC)) {
-               /* Our command was replied to, kill the retry timer */
-               del_timer(&gsm->t2_timer);
-               gsm->pending_cmd = NULL;
-               /* Rejected by the other end */
-               if (command == CMD_NSC)
-                       ctrl->error = -EOPNOTSUPP;
-               ctrl->done = 1;
-               wake_up(&gsm->event);
-       }
-       spin_unlock_irqrestore(&gsm->control_lock, flags);
-}
-
-/**
- *     gsm_control_transmit    -       send control packet
- *     @gsm: gsm mux
- *     @ctrl: frame to send
- *
- *     Send out a pending control command (called under control lock)
- */
-
-static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl)
-{
-       struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 1,
-                                                       gsm->ftype|PF);
-       if (msg == NULL)
-               return;
-       msg->data[0] = (ctrl->cmd << 1) | 2 | EA;       /* command */
-       memcpy(msg->data + 1, ctrl->data, ctrl->len);
-       gsm_data_queue(gsm->dlci[0], msg);
-}
-
-/**
- *     gsm_control_retransmit  -       retransmit a control frame
- *     @data: pointer to our gsm object
- *
- *     Called off the T2 timer expiry in order to retransmit control frames
- *     that have been lost in the system somewhere. The control_lock protects
- *     us from colliding with another sender or a receive completion event.
- *     In that situation the timer may still occur in a small window but
- *     gsm->pending_cmd will be NULL and we just let the timer expire.
- */
-
-static void gsm_control_retransmit(unsigned long data)
-{
-       struct gsm_mux *gsm = (struct gsm_mux *)data;
-       struct gsm_control *ctrl;
-       unsigned long flags;
-       spin_lock_irqsave(&gsm->control_lock, flags);
-       ctrl = gsm->pending_cmd;
-       if (ctrl) {
-               gsm->cretries--;
-               if (gsm->cretries == 0) {
-                       gsm->pending_cmd = NULL;
-                       ctrl->error = -ETIMEDOUT;
-                       ctrl->done = 1;
-                       spin_unlock_irqrestore(&gsm->control_lock, flags);
-                       wake_up(&gsm->event);
-                       return;
-               }
-               gsm_control_transmit(gsm, ctrl);
-               mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
-       }
-       spin_unlock_irqrestore(&gsm->control_lock, flags);
-}
-
-/**
- *     gsm_control_send        -       send a control frame on DLCI 0
- *     @gsm: the GSM channel
- *     @command: command  to send including CR bit
- *     @data: bytes of data (must be kmalloced)
- *     @len: length of the block to send
- *
- *     Queue and dispatch a control command. Only one command can be
- *     active at a time. In theory more can be outstanding but the matching
- *     gets really complicated so for now stick to one outstanding.
- */
-
-static struct gsm_control *gsm_control_send(struct gsm_mux *gsm,
-               unsigned int command, u8 *data, int clen)
-{
-       struct gsm_control *ctrl = kzalloc(sizeof(struct gsm_control),
-                                               GFP_KERNEL);
-       unsigned long flags;
-       if (ctrl == NULL)
-               return NULL;
-retry:
-       wait_event(gsm->event, gsm->pending_cmd == NULL);
-       spin_lock_irqsave(&gsm->control_lock, flags);
-       if (gsm->pending_cmd != NULL) {
-               spin_unlock_irqrestore(&gsm->control_lock, flags);
-               goto retry;
-       }
-       ctrl->cmd = command;
-       ctrl->data = data;
-       ctrl->len = clen;
-       gsm->pending_cmd = ctrl;
-       gsm->cretries = gsm->n2;
-       mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
-       gsm_control_transmit(gsm, ctrl);
-       spin_unlock_irqrestore(&gsm->control_lock, flags);
-       return ctrl;
-}
-
-/**
- *     gsm_control_wait        -       wait for a control to finish
- *     @gsm: GSM mux
- *     @control: control we are waiting on
- *
- *     Waits for the control to complete or time out. Frees any used
- *     resources and returns 0 for success, or an error if the remote
- *     rejected or ignored the request.
- */
-
-static int gsm_control_wait(struct gsm_mux *gsm, struct gsm_control *control)
-{
-       int err;
-       wait_event(gsm->event, control->done == 1);
-       err = control->error;
-       kfree(control);
-       return err;
-}
-
-
-/*
- *     DLCI level handling: Needs krefs
- */
-
-/*
- *     State transitions and timers
- */
-
-/**
- *     gsm_dlci_close          -       a DLCI has closed
- *     @dlci: DLCI that closed
- *
- *     Perform processing when moving a DLCI into closed state. If there
- *     is an attached tty this is hung up
- */
-
-static void gsm_dlci_close(struct gsm_dlci *dlci)
-{
-       del_timer(&dlci->t1);
-       if (debug & 8)
-               printk("DLCI %d goes closed.\n", dlci->addr);
-       dlci->state = DLCI_CLOSED;
-       if (dlci->addr != 0) {
-               struct tty_struct  *tty = tty_port_tty_get(&dlci->port);
-               if (tty) {
-                       tty_hangup(tty);
-                       tty_kref_put(tty);
-               }
-               kfifo_reset(dlci->fifo);
-       } else
-               dlci->gsm->dead = 1;
-       wake_up(&dlci->gsm->event);
-       /* A DLCI 0 close is a MUX termination so we need to kick that
-          back to userspace somehow */
-}
-
-/**
- *     gsm_dlci_open           -       a DLCI has opened
- *     @dlci: DLCI that opened
- *
- *     Perform processing when moving a DLCI into open state.
- */
-
-static void gsm_dlci_open(struct gsm_dlci *dlci)
-{
-       /* Note that SABM UA .. SABM UA first UA lost can mean that we go
-          open -> open */
-       del_timer(&dlci->t1);
-       /* This will let a tty open continue */
-       dlci->state = DLCI_OPEN;
-       if (debug & 8)
-               printk("DLCI %d goes open.\n", dlci->addr);
-       wake_up(&dlci->gsm->event);
-}
-
-/**
- *     gsm_dlci_t1             -       T1 timer expiry
- *     @dlci: DLCI that opened
- *
- *     The T1 timer handles retransmits of control frames (essentially of
- *     SABM and DISC). We resend the command until the retry count runs out
- *     in which case an opening port goes back to closed and a closing port
- *     is simply put into closed state (any further frames from the other
- *     end will get a DM response)
- */
-
-static void gsm_dlci_t1(unsigned long data)
-{
-       struct gsm_dlci *dlci = (struct gsm_dlci *)data;
-       struct gsm_mux *gsm = dlci->gsm;
-
-       switch (dlci->state) {
-       case DLCI_OPENING:
-               dlci->retries--;
-               if (dlci->retries) {
-                       gsm_command(dlci->gsm, dlci->addr, SABM|PF);
-                       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-               } else
-                       gsm_dlci_close(dlci);
-               break;
-       case DLCI_CLOSING:
-               dlci->retries--;
-               if (dlci->retries) {
-                       gsm_command(dlci->gsm, dlci->addr, DISC|PF);
-                       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-               } else
-                       gsm_dlci_close(dlci);
-               break;
-       }
-}
-
-/**
- *     gsm_dlci_begin_open     -       start channel open procedure
- *     @dlci: DLCI to open
- *
- *     Commence opening a DLCI from the Linux side. We issue SABM messages
- *     to the modem which should then reply with a UA, at which point we
- *     will move into open state. Opening is done asynchronously with retry
- *     running off timers and the responses.
- */
-
-static void gsm_dlci_begin_open(struct gsm_dlci *dlci)
-{
-       struct gsm_mux *gsm = dlci->gsm;
-       if (dlci->state == DLCI_OPEN || dlci->state == DLCI_OPENING)
-               return;
-       dlci->retries = gsm->n2;
-       dlci->state = DLCI_OPENING;
-       gsm_command(dlci->gsm, dlci->addr, SABM|PF);
-       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-}
-
-/**
- *     gsm_dlci_begin_close    -       start channel open procedure
- *     @dlci: DLCI to open
- *
- *     Commence closing a DLCI from the Linux side. We issue DISC messages
- *     to the modem which should then reply with a UA, at which point we
- *     will move into closed state. Closing is done asynchronously with retry
- *     off timers. We may also receive a DM reply from the other end which
- *     indicates the channel was already closed.
- */
-
-static void gsm_dlci_begin_close(struct gsm_dlci *dlci)
-{
-       struct gsm_mux *gsm = dlci->gsm;
-       if (dlci->state == DLCI_CLOSED || dlci->state == DLCI_CLOSING)
-               return;
-       dlci->retries = gsm->n2;
-       dlci->state = DLCI_CLOSING;
-       gsm_command(dlci->gsm, dlci->addr, DISC|PF);
-       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-}
-
-/**
- *     gsm_dlci_data           -       data arrived
- *     @dlci: channel
- *     @data: block of bytes received
- *     @len: length of received block
- *
- *     A UI or UIH frame has arrived which contains data for a channel
- *     other than the control channel. If the relevant virtual tty is
- *     open we shovel the bits down it, if not we drop them.
- */
-
-static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len)
-{
-       /* krefs .. */
-       struct tty_port *port = &dlci->port;
-       struct tty_struct *tty = tty_port_tty_get(port);
-       unsigned int modem = 0;
-
-       if (debug & 16)
-               printk("%d bytes for tty %p\n", len, tty);
-       if (tty) {
-               switch (dlci->adaption)  {
-                       /* Unsupported types */
-                       /* Packetised interruptible data */
-                       case 4:
-                               break;
-                       /* Packetised uininterruptible voice/data */
-                       case 3:
-                               break;
-                       /* Asynchronous serial with line state in each frame */
-                       case 2:
-                               while (gsm_read_ea(&modem, *data++) == 0) {
-                                       len--;
-                                       if (len == 0)
-                                               return;
-                               }
-                               gsm_process_modem(tty, dlci, modem);
-                       /* Line state will go via DLCI 0 controls only */
-                       case 1:
-                       default:
-                               tty_insert_flip_string(tty, data, len);
-                               tty_flip_buffer_push(tty);
-               }
-               tty_kref_put(tty);
-       }
-}
-
-/**
- *     gsm_dlci_control        -       data arrived on control channel
- *     @dlci: channel
- *     @data: block of bytes received
- *     @len: length of received block
- *
- *     A UI or UIH frame has arrived which contains data for DLCI 0 the
- *     control channel. This should contain a command EA followed by
- *     control data bytes. The command EA contains a command/response bit
- *     and we divide up the work accordingly.
- */
-
-static void gsm_dlci_command(struct gsm_dlci *dlci, u8 *data, int len)
-{
-       /* See what command is involved */
-       unsigned int command = 0;
-       while (len-- > 0) {
-               if (gsm_read_ea(&command, *data++) == 1) {
-                       int clen = *data++;
-                       len--;
-                       /* FIXME: this is properly an EA */
-                       clen >>= 1;
-                       /* Malformed command ? */
-                       if (clen > len)
-                               return;
-                       if (command & 1)
-                               gsm_control_message(dlci->gsm, command,
-                                                               data, clen);
-                       else
-                               gsm_control_response(dlci->gsm, command,
-                                                               data, clen);
-                       return;
-               }
-       }
-}
-
-/*
- *     Allocate/Free DLCI channels
- */
-
-/**
- *     gsm_dlci_alloc          -       allocate a DLCI
- *     @gsm: GSM mux
- *     @addr: address of the DLCI
- *
- *     Allocate and install a new DLCI object into the GSM mux.
- *
- *     FIXME: review locking races
- */
-
-static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
-{
-       struct gsm_dlci *dlci = kzalloc(sizeof(struct gsm_dlci), GFP_ATOMIC);
-       if (dlci == NULL)
-               return NULL;
-       spin_lock_init(&dlci->lock);
-       dlci->fifo = &dlci->_fifo;
-       if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) {
-               kfree(dlci);
-               return NULL;
-       }
-
-       skb_queue_head_init(&dlci->skb_list);
-       init_timer(&dlci->t1);
-       dlci->t1.function = gsm_dlci_t1;
-       dlci->t1.data = (unsigned long)dlci;
-       tty_port_init(&dlci->port);
-       dlci->port.ops = &gsm_port_ops;
-       dlci->gsm = gsm;
-       dlci->addr = addr;
-       dlci->adaption = gsm->adaption;
-       dlci->state = DLCI_CLOSED;
-       if (addr)
-               dlci->data = gsm_dlci_data;
-       else
-               dlci->data = gsm_dlci_command;
-       gsm->dlci[addr] = dlci;
-       return dlci;
-}
-
-/**
- *     gsm_dlci_free           -       release DLCI
- *     @dlci: DLCI to destroy
- *
- *     Free up a DLCI. Currently to keep the lifetime rules sane we only
- *     clean up DLCI objects when the MUX closes rather than as the port
- *     is closed down on both the tty and mux levels.
- *
- *     Can sleep.
- */
-static void gsm_dlci_free(struct gsm_dlci *dlci)
-{
-       struct tty_struct *tty = tty_port_tty_get(&dlci->port);
-       if (tty) {
-               tty_vhangup(tty);
-               tty_kref_put(tty);
-       }
-       del_timer_sync(&dlci->t1);
-       dlci->gsm->dlci[dlci->addr] = NULL;
-       kfifo_free(dlci->fifo);
-       kfree(dlci);
-}
-
-
-/*
- *     LAPBish link layer logic
- */
-
-/**
- *     gsm_queue               -       a GSM frame is ready to process
- *     @gsm: pointer to our gsm mux
- *
- *     At this point in time a frame has arrived and been demangled from
- *     the line encoding. All the differences between the encodings have
- *     been handled below us and the frame is unpacked into the structures.
- *     The fcs holds the header FCS but any data FCS must be added here.
- */
-
-static void gsm_queue(struct gsm_mux *gsm)
-{
-       struct gsm_dlci *dlci;
-       u8 cr;
-       int address;
-       /* We have to sneak a look at the packet body to do the FCS.
-          A somewhat layering violation in the spec */
-
-       if ((gsm->control & ~PF) == UI)
-               gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
-       if (gsm->fcs != GOOD_FCS) {
-               gsm->bad_fcs++;
-               if (debug & 4)
-                       printk("BAD FCS %02x\n", gsm->fcs);
-               return;
-       }
-       address = gsm->address >> 1;
-       if (address >= NUM_DLCI)
-               goto invalid;
-
-       cr = gsm->address & 1;          /* C/R bit */
-
-       gsm_print_packet("<--", address, cr, gsm->control, gsm->buf, gsm->len);
-
-       cr ^= 1 - gsm->initiator;       /* Flip so 1 always means command */
-       dlci = gsm->dlci[address];
-
-       switch (gsm->control) {
-       case SABM|PF:
-               if (cr == 0)
-                       goto invalid;
-               if (dlci == NULL)
-                       dlci = gsm_dlci_alloc(gsm, address);
-               if (dlci == NULL)
-                       return;
-               if (dlci->dead)
-                       gsm_response(gsm, address, DM);
-               else {
-                       gsm_response(gsm, address, UA);
-                       gsm_dlci_open(dlci);
-               }
-               break;
-       case DISC|PF:
-               if (cr == 0)
-                       goto invalid;
-               if (dlci == NULL || dlci->state == DLCI_CLOSED) {
-                       gsm_response(gsm, address, DM);
-                       return;
-               }
-               /* Real close complete */
-               gsm_response(gsm, address, UA);
-               gsm_dlci_close(dlci);
-               break;
-       case UA:
-       case UA|PF:
-               if (cr == 0 || dlci == NULL)
-                       break;
-               switch (dlci->state) {
-               case DLCI_CLOSING:
-                       gsm_dlci_close(dlci);
-                       break;
-               case DLCI_OPENING:
-                       gsm_dlci_open(dlci);
-                       break;
-               }
-               break;
-       case DM:        /* DM can be valid unsolicited */
-       case DM|PF:
-               if (cr)
-                       goto invalid;
-               if (dlci == NULL)
-                       return;
-               gsm_dlci_close(dlci);
-               break;
-       case UI:
-       case UI|PF:
-       case UIH:
-       case UIH|PF:
-#if 0
-               if (cr)
-                       goto invalid;
-#endif
-               if (dlci == NULL || dlci->state != DLCI_OPEN) {
-                       gsm_command(gsm, address, DM|PF);
-                       return;
-               }
-               dlci->data(dlci, gsm->buf, gsm->len);
-               break;
-       default:
-               goto invalid;
-       }
-       return;
-invalid:
-       gsm->malformed++;
-       return;
-}
-
-
-/**
- *     gsm0_receive    -       perform processing for non-transparency
- *     @gsm: gsm data for this ldisc instance
- *     @c: character
- *
- *     Receive bytes in gsm mode 0
- */
-
-static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
-{
-       switch (gsm->state) {
-       case GSM_SEARCH:        /* SOF marker */
-               if (c == GSM0_SOF) {
-                       gsm->state = GSM_ADDRESS;
-                       gsm->address = 0;
-                       gsm->len = 0;
-                       gsm->fcs = INIT_FCS;
-               }
-               break;          /* Address EA */
-       case GSM_ADDRESS:
-               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-               if (gsm_read_ea(&gsm->address, c))
-                       gsm->state = GSM_CONTROL;
-               break;
-       case GSM_CONTROL:       /* Control Byte */
-               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-               gsm->control = c;
-               gsm->state = GSM_LEN;
-               break;
-       case GSM_LEN:           /* Length EA */
-               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-               if (gsm_read_ea(&gsm->len, c)) {
-                       if (gsm->len > gsm->mru) {
-                               gsm->bad_size++;
-                               gsm->state = GSM_SEARCH;
-                               break;
-                       }
-                       gsm->count = 0;
-                       gsm->state = GSM_DATA;
-               }
-               break;
-       case GSM_DATA:          /* Data */
-               gsm->buf[gsm->count++] = c;
-               if (gsm->count == gsm->len)
-                       gsm->state = GSM_FCS;
-               break;
-       case GSM_FCS:           /* FCS follows the packet */
-               gsm->fcs = c;
-               gsm_queue(gsm);
-               /* And then back for the next frame */
-               gsm->state = GSM_SEARCH;
-               break;
-       }
-}
-
-/**
- *     gsm0_receive    -       perform processing for non-transparency
- *     @gsm: gsm data for this ldisc instance
- *     @c: character
- *
- *     Receive bytes in mode 1 (Advanced option)
- */
-
-static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
-{
-       if (c == GSM1_SOF) {
-               /* EOF is only valid in frame if we have got to the data state
-                  and received at least one byte (the FCS) */
-               if (gsm->state == GSM_DATA && gsm->count) {
-                       /* Extract the FCS */
-                       gsm->count--;
-                       gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]);
-                       gsm->len = gsm->count;
-                       gsm_queue(gsm);
-                       gsm->state  = GSM_START;
-                       return;
-               }
-               /* Any partial frame was a runt so go back to start */
-               if (gsm->state != GSM_START) {
-                       gsm->malformed++;
-                       gsm->state = GSM_START;
-               }
-               /* A SOF in GSM_START means we are still reading idling or
-                  framing bytes */
-               return;
-       }
-
-       if (c == GSM1_ESCAPE) {
-               gsm->escape = 1;
-               return;
-       }
-
-       /* Only an unescaped SOF gets us out of GSM search */
-       if (gsm->state == GSM_SEARCH)
-               return;
-
-       if (gsm->escape) {
-               c ^= GSM1_ESCAPE_BITS;
-               gsm->escape = 0;
-       }
-       switch (gsm->state) {
-       case GSM_START:         /* First byte after SOF */
-               gsm->address = 0;
-               gsm->state = GSM_ADDRESS;
-               gsm->fcs = INIT_FCS;
-               /* Drop through */
-       case GSM_ADDRESS:       /* Address continuation */
-               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-               if (gsm_read_ea(&gsm->address, c))
-                       gsm->state = GSM_CONTROL;
-               break;
-       case GSM_CONTROL:       /* Control Byte */
-               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-               gsm->control = c;
-               gsm->count = 0;
-               gsm->state = GSM_DATA;
-               break;
-       case GSM_DATA:          /* Data */
-               if (gsm->count > gsm->mru ) {   /* Allow one for the FCS */
-                       gsm->state = GSM_OVERRUN;
-                       gsm->bad_size++;
-               } else
-                       gsm->buf[gsm->count++] = c;
-               break;
-       case GSM_OVERRUN:       /* Over-long - eg a dropped SOF */
-               break;
-       }
-}
-
-/**
- *     gsm_error               -       handle tty error
- *     @gsm: ldisc data
- *     @data: byte received (may be invalid)
- *     @flag: error received
- *
- *     Handle an error in the receipt of data for a frame. Currently we just
- *     go back to hunting for a SOF.
- *
- *     FIXME: better diagnostics ?
- */
-
-static void gsm_error(struct gsm_mux *gsm,
-                               unsigned char data, unsigned char flag)
-{
-       gsm->state = GSM_SEARCH;
-       gsm->io_error++;
-}
-
-/**
- *     gsm_cleanup_mux         -       generic GSM protocol cleanup
- *     @gsm: our mux
- *
- *     Clean up the bits of the mux which are the same for all framing
- *     protocols. Remove the mux from the mux table, stop all the timers
- *     and then shut down each device hanging up the channels as we go.
- */
-
-void gsm_cleanup_mux(struct gsm_mux *gsm)
-{
-       int i;
-       struct gsm_dlci *dlci = gsm->dlci[0];
-       struct gsm_msg *txq;
-
-       gsm->dead = 1;
-
-       spin_lock(&gsm_mux_lock);
-       for (i = 0; i < MAX_MUX; i++) {
-               if (gsm_mux[i] == gsm) {
-                       gsm_mux[i] = NULL;
-                       break;
-               }
-       }
-       spin_unlock(&gsm_mux_lock);
-       WARN_ON(i == MAX_MUX);
-
-       del_timer_sync(&gsm->t2_timer);
-       /* Now we are sure T2 has stopped */
-       if (dlci) {
-               dlci->dead = 1;
-               gsm_dlci_begin_close(dlci);
-               wait_event_interruptible(gsm->event,
-                                       dlci->state == DLCI_CLOSED);
-       }
-       /* Free up any link layer users */
-       for (i = 0; i < NUM_DLCI; i++)
-               if (gsm->dlci[i])
-                       gsm_dlci_free(gsm->dlci[i]);
-       /* Now wipe the queues */
-       for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) {
-               gsm->tx_head = txq->next;
-               kfree(txq);
-       }
-       gsm->tx_tail = NULL;
-}
-EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
-
-/**
- *     gsm_activate_mux        -       generic GSM setup
- *     @gsm: our mux
- *
- *     Set up the bits of the mux which are the same for all framing
- *     protocols. Add the mux to the mux table so it can be opened and
- *     finally kick off connecting to DLCI 0 on the modem.
- */
-
-int gsm_activate_mux(struct gsm_mux *gsm)
-{
-       struct gsm_dlci *dlci;
-       int i = 0;
-
-       init_timer(&gsm->t2_timer);
-       gsm->t2_timer.function = gsm_control_retransmit;
-       gsm->t2_timer.data = (unsigned long)gsm;
-       init_waitqueue_head(&gsm->event);
-       spin_lock_init(&gsm->control_lock);
-       spin_lock_init(&gsm->tx_lock);
-
-       if (gsm->encoding == 0)
-               gsm->receive = gsm0_receive;
-       else
-               gsm->receive = gsm1_receive;
-       gsm->error = gsm_error;
-
-       spin_lock(&gsm_mux_lock);
-       for (i = 0; i < MAX_MUX; i++) {
-               if (gsm_mux[i] == NULL) {
-                       gsm_mux[i] = gsm;
-                       break;
-               }
-       }
-       spin_unlock(&gsm_mux_lock);
-       if (i == MAX_MUX)
-               return -EBUSY;
-
-       dlci = gsm_dlci_alloc(gsm, 0);
-       if (dlci == NULL)
-               return -ENOMEM;
-       gsm->dead = 0;          /* Tty opens are now permissible */
-       return 0;
-}
-EXPORT_SYMBOL_GPL(gsm_activate_mux);
-
-/**
- *     gsm_free_mux            -       free up a mux
- *     @mux: mux to free
- *
- *     Dispose of allocated resources for a dead mux. No refcounting
- *     at present so the mux must be truely dead.
- */
-void gsm_free_mux(struct gsm_mux *gsm)
-{
-       kfree(gsm->txframe);
-       kfree(gsm->buf);
-       kfree(gsm);
-}
-EXPORT_SYMBOL_GPL(gsm_free_mux);
-
-/**
- *     gsm_alloc_mux           -       allocate a mux
- *
- *     Creates a new mux ready for activation.
- */
-
-struct gsm_mux *gsm_alloc_mux(void)
-{
-       struct gsm_mux *gsm = kzalloc(sizeof(struct gsm_mux), GFP_KERNEL);
-       if (gsm == NULL)
-               return NULL;
-       gsm->buf = kmalloc(MAX_MRU + 1, GFP_KERNEL);
-       if (gsm->buf == NULL) {
-               kfree(gsm);
-               return NULL;
-       }
-       gsm->txframe = kmalloc(2 * MAX_MRU + 2, GFP_KERNEL);
-       if (gsm->txframe == NULL) {
-               kfree(gsm->buf);
-               kfree(gsm);
-               return NULL;
-       }
-       spin_lock_init(&gsm->lock);
-
-       gsm->t1 = T1;
-       gsm->t2 = T2;
-       gsm->n2 = N2;
-       gsm->ftype = UIH;
-       gsm->initiator = 0;
-       gsm->adaption = 1;
-       gsm->encoding = 1;
-       gsm->mru = 64;  /* Default to encoding 1 so these should be 64 */
-       gsm->mtu = 64;
-       gsm->dead = 1;  /* Avoid early tty opens */
-
-       return gsm;
-}
-EXPORT_SYMBOL_GPL(gsm_alloc_mux);
-
-
-
-
-/**
- *     gsmld_output            -       write to link
- *     @gsm: our mux
- *     @data: bytes to output
- *     @len: size
- *
- *     Write a block of data from the GSM mux to the data channel. This
- *     will eventually be serialized from above but at the moment isn't.
- */
-
-static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
-{
-       if (tty_write_room(gsm->tty) < len) {
-               set_bit(TTY_DO_WRITE_WAKEUP, &gsm->tty->flags);
-               return -ENOSPC;
-       }
-       if (debug & 4) {
-               printk("-->%d bytes out\n", len);
-               hex_packet(data, len);
-       }
-       gsm->tty->ops->write(gsm->tty, data, len);
-       return len;
-}
-
-/**
- *     gsmld_attach_gsm        -       mode set up
- *     @tty: our tty structure
- *     @gsm: our mux
- *
- *     Set up the MUX for basic mode and commence connecting to the
- *     modem. Currently called from the line discipline set up but
- *     will need moving to an ioctl path.
- */
-
-static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
-{
-       int ret;
-
-       gsm->tty = tty_kref_get(tty);
-       gsm->output = gsmld_output;
-       ret =  gsm_activate_mux(gsm);
-       if (ret != 0)
-               tty_kref_put(gsm->tty);
-       return ret;
-}
-
-
-/**
- *     gsmld_detach_gsm        -       stop doing 0710 mux
- *     @tty: tty atttached to the mux
- *     @gsm: mux
- *
- *     Shutdown and then clean up the resources used by the line discipline
- */
-
-static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
-{
-       WARN_ON(tty != gsm->tty);
-       gsm_cleanup_mux(gsm);
-       tty_kref_put(gsm->tty);
-       gsm->tty = NULL;
-}
-
-static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-                             char *fp, int count)
-{
-       struct gsm_mux *gsm = tty->disc_data;
-       const unsigned char *dp;
-       char *f;
-       int i;
-       char buf[64];
-       char flags;
-
-       if (debug & 4) {
-               printk("Inbytes %dd\n", count);
-               hex_packet(cp, count);
-       }
-
-       for (i = count, dp = cp, f = fp; i; i--, dp++) {
-               flags = *f++;
-               switch (flags) {
-               case TTY_NORMAL:
-                       gsm->receive(gsm, *dp);
-                       break;
-               case TTY_OVERRUN:
-               case TTY_BREAK:
-               case TTY_PARITY:
-               case TTY_FRAME:
-                       gsm->error(gsm, *dp, flags);
-                       break;
-               default:
-                       printk(KERN_ERR "%s: unknown flag %d\n",
-                              tty_name(tty, buf), flags);
-                       break;
-               }
-       }
-       /* FASYNC if needed ? */
-       /* If clogged call tty_throttle(tty); */
-}
-
-/**
- *     gsmld_chars_in_buffer   -       report available bytes
- *     @tty: tty device
- *
- *     Report the number of characters buffered to be delivered to user
- *     at this instant in time.
- *
- *     Locking: gsm lock
- */
-
-static ssize_t gsmld_chars_in_buffer(struct tty_struct *tty)
-{
-       return 0;
-}
-
-/**
- *     gsmld_flush_buffer      -       clean input queue
- *     @tty:   terminal device
- *
- *     Flush the input buffer. Called when the line discipline is
- *     being closed, when the tty layer wants the buffer flushed (eg
- *     at hangup).
- */
-
-static void gsmld_flush_buffer(struct tty_struct *tty)
-{
-}
-
-/**
- *     gsmld_close             -       close the ldisc for this tty
- *     @tty: device
- *
- *     Called from the terminal layer when this line discipline is
- *     being shut down, either because of a close or becsuse of a
- *     discipline change. The function will not be called while other
- *     ldisc methods are in progress.
- */
-
-static void gsmld_close(struct tty_struct *tty)
-{
-       struct gsm_mux *gsm = tty->disc_data;
-
-       gsmld_detach_gsm(tty, gsm);
-
-       gsmld_flush_buffer(tty);
-       /* Do other clean up here */
-       gsm_free_mux(gsm);
-}
-
-/**
- *     gsmld_open              -       open an ldisc
- *     @tty: terminal to open
- *
- *     Called when this line discipline is being attached to the
- *     terminal device. Can sleep. Called serialized so that no
- *     other events will occur in parallel. No further open will occur
- *     until a close.
- */
-
-static int gsmld_open(struct tty_struct *tty)
-{
-       struct gsm_mux *gsm;
-
-       if (tty->ops->write == NULL)
-               return -EINVAL;
-
-       /* Attach our ldisc data */
-       gsm = gsm_alloc_mux();
-       if (gsm == NULL)
-               return -ENOMEM;
-
-       tty->disc_data = gsm;
-       tty->receive_room = 65536;
-
-       /* Attach the initial passive connection */
-       gsm->encoding = 1;
-       return gsmld_attach_gsm(tty, gsm);
-}
-
-/**
- *     gsmld_write_wakeup      -       asynchronous I/O notifier
- *     @tty: tty device
- *
- *     Required for the ptys, serial driver etc. since processes
- *     that attach themselves to the master and rely on ASYNC
- *     IO must be woken up
- */
-
-static void gsmld_write_wakeup(struct tty_struct *tty)
-{
-       struct gsm_mux *gsm = tty->disc_data;
-       unsigned long flags;
-
-       /* Queue poll */
-       clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-       gsm_data_kick(gsm);
-       if (gsm->tx_bytes < TX_THRESH_LO) {
-               spin_lock_irqsave(&gsm->tx_lock, flags);
-               gsm_dlci_data_sweep(gsm);
-               spin_unlock_irqrestore(&gsm->tx_lock, flags);
-       }
-}
-
-/**
- *     gsmld_read              -       read function for tty
- *     @tty: tty device
- *     @file: file object
- *     @buf: userspace buffer pointer
- *     @nr: size of I/O
- *
- *     Perform reads for the line discipline. We are guaranteed that the
- *     line discipline will not be closed under us but we may get multiple
- *     parallel readers and must handle this ourselves. We may also get
- *     a hangup. Always called in user context, may sleep.
- *
- *     This code must be sure never to sleep through a hangup.
- */
-
-static ssize_t gsmld_read(struct tty_struct *tty, struct file *file,
-                        unsigned char __user *buf, size_t nr)
-{
-       return -EOPNOTSUPP;
-}
-
-/**
- *     gsmld_write             -       write function for tty
- *     @tty: tty device
- *     @file: file object
- *     @buf: userspace buffer pointer
- *     @nr: size of I/O
- *
- *     Called when the owner of the device wants to send a frame
- *     itself (or some other control data). The data is transferred
- *     as-is and must be properly framed and checksummed as appropriate
- *     by userspace. Frames are either sent whole or not at all as this
- *     avoids pain user side.
- */
-
-static ssize_t gsmld_write(struct tty_struct *tty, struct file *file,
-                          const unsigned char *buf, size_t nr)
-{
-       int space = tty_write_room(tty);
-       if (space >= nr)
-               return tty->ops->write(tty, buf, nr);
-       set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-       return -ENOBUFS;
-}
-
-/**
- *     gsmld_poll              -       poll method for N_GSM0710
- *     @tty: terminal device
- *     @file: file accessing it
- *     @wait: poll table
- *
- *     Called when the line discipline is asked to poll() for data or
- *     for special events. This code is not serialized with respect to
- *     other events save open/close.
- *
- *     This code must be sure never to sleep through a hangup.
- *     Called without the kernel lock held - fine
- */
-
-static unsigned int gsmld_poll(struct tty_struct *tty, struct file *file,
-                                                       poll_table *wait)
-{
-       unsigned int mask = 0;
-       struct gsm_mux *gsm = tty->disc_data;
-
-       poll_wait(file, &tty->read_wait, wait);
-       poll_wait(file, &tty->write_wait, wait);
-       if (tty_hung_up_p(file))
-               mask |= POLLHUP;
-       if (!tty_is_writelocked(tty) && tty_write_room(tty) > 0)
-               mask |= POLLOUT | POLLWRNORM;
-       if (gsm->dead)
-               mask |= POLLHUP;
-       return mask;
-}
-
-static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
-                                                       struct gsm_config *c)
-{
-       int need_close = 0;
-       int need_restart = 0;
-
-       /* Stuff we don't support yet - UI or I frame transport, windowing */
-       if ((c->adaption !=1 && c->adaption != 2) || c->k)
-               return -EOPNOTSUPP;
-       /* Check the MRU/MTU range looks sane */
-       if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8)
-               return -EINVAL;
-       if (c->n2 < 3)
-               return -EINVAL;
-       if (c->encapsulation > 1)       /* Basic, advanced, no I */
-               return -EINVAL;
-       if (c->initiator > 1)
-               return -EINVAL;
-       if (c->i == 0 || c->i > 2)      /* UIH and UI only */
-               return -EINVAL;
-       /*
-        *      See what is needed for reconfiguration
-        */
-
-       /* Timing fields */
-       if (c->t1 != 0 && c->t1 != gsm->t1)
-               need_restart = 1;
-       if (c->t2 != 0 && c->t2 != gsm->t2)
-               need_restart = 1;
-       if (c->encapsulation != gsm->encoding)
-               need_restart = 1;
-       if (c->adaption != gsm->adaption)
-               need_restart = 1;
-       /* Requires care */
-       if (c->initiator != gsm->initiator)
-               need_close = 1;
-       if (c->mru != gsm->mru)
-               need_restart = 1;
-       if (c->mtu != gsm->mtu)
-               need_restart = 1;
-
-       /*
-        *      Close down what is needed, restart and initiate the new
-        *      configuration
-        */
-
-       if (need_close || need_restart) {
-               gsm_dlci_begin_close(gsm->dlci[0]);
-               /* This will timeout if the link is down due to N2 expiring */
-               wait_event_interruptible(gsm->event,
-                               gsm->dlci[0]->state == DLCI_CLOSED);
-               if (signal_pending(current))
-                       return -EINTR;
-       }
-       if (need_restart)
-               gsm_cleanup_mux(gsm);
-
-       gsm->initiator = c->initiator;
-       gsm->mru = c->mru;
-       gsm->encoding = c->encapsulation;
-       gsm->adaption = c->adaption;
-
-       if (c->i == 1)
-               gsm->ftype = UIH;
-       else if (c->i == 2)
-               gsm->ftype = UI;
-
-       if (c->t1)
-               gsm->t1 = c->t1;
-       if (c->t2)
-               gsm->t2 = c->t2;
-
-       /* FIXME: We need to separate activation/deactivation from adding
-          and removing from the mux array */
-       if (need_restart)
-               gsm_activate_mux(gsm);
-       if (gsm->initiator && need_close)
-               gsm_dlci_begin_open(gsm->dlci[0]);
-       return 0;
-}
-
-static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       struct gsm_config c;
-       struct gsm_mux *gsm = tty->disc_data;
-
-       switch (cmd) {
-       case GSMIOC_GETCONF:
-               memset(&c, 0, sizeof(c));
-               c.adaption = gsm->adaption;
-               c.encapsulation = gsm->encoding;
-               c.initiator = gsm->initiator;
-               c.t1 = gsm->t1;
-               c.t2 = gsm->t2;
-               c.t3 = 0;       /* Not supported */
-               c.n2 = gsm->n2;
-               if (gsm->ftype == UIH)
-                       c.i = 1;
-               else
-                       c.i = 2;
-               printk("Ftype %d i %d\n", gsm->ftype, c.i);
-               c.mru = gsm->mru;
-               c.mtu = gsm->mtu;
-               c.k = 0;
-               if (copy_to_user((void *)arg, &c, sizeof(c)))
-                       return -EFAULT;
-               return 0;
-       case GSMIOC_SETCONF:
-               if (copy_from_user(&c, (void *)arg, sizeof(c)))
-                       return -EFAULT;
-               return gsmld_config(tty, gsm, &c);
-       default:
-               return n_tty_ioctl_helper(tty, file, cmd, arg);
-       }
-}
-
-
-/* Line discipline for real tty */
-struct tty_ldisc_ops tty_ldisc_packet = {
-       .owner           = THIS_MODULE,
-       .magic           = TTY_LDISC_MAGIC,
-       .name            = "n_gsm",
-       .open            = gsmld_open,
-       .close           = gsmld_close,
-       .flush_buffer    = gsmld_flush_buffer,
-       .chars_in_buffer = gsmld_chars_in_buffer,
-       .read            = gsmld_read,
-       .write           = gsmld_write,
-       .ioctl           = gsmld_ioctl,
-       .poll            = gsmld_poll,
-       .receive_buf     = gsmld_receive_buf,
-       .write_wakeup    = gsmld_write_wakeup
-};
-
-/*
- *     Virtual tty side
- */
-
-#define TX_SIZE                512
-
-static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
-{
-       u8 modembits[5];
-       struct gsm_control *ctrl;
-       int len = 2;
-
-       if (brk)
-               len++;
-
-       modembits[0] = len << 1 | EA;           /* Data bytes */
-       modembits[1] = dlci->addr << 2 | 3;     /* DLCI, EA, 1 */
-       modembits[2] = gsm_encode_modem(dlci) << 1 | EA;
-       if (brk)
-               modembits[3] = brk << 4 | 2 | EA;       /* Valid, EA */
-       ctrl = gsm_control_send(dlci->gsm, CMD_MSC, modembits, len + 1);
-       if (ctrl == NULL)
-               return -ENOMEM;
-       return gsm_control_wait(dlci->gsm, ctrl);
-}
-
-static int gsm_carrier_raised(struct tty_port *port)
-{
-       struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
-       /* Not yet open so no carrier info */
-       if (dlci->state != DLCI_OPEN)
-               return 0;
-       if (debug & 2)
-               return 1;
-       return dlci->modem_rx & TIOCM_CD;
-}
-
-static void gsm_dtr_rts(struct tty_port *port, int onoff)
-{
-       struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
-       unsigned int modem_tx = dlci->modem_tx;
-       if (onoff)
-               modem_tx |= TIOCM_DTR | TIOCM_RTS;
-       else
-               modem_tx &= ~(TIOCM_DTR | TIOCM_RTS);
-       if (modem_tx != dlci->modem_tx) {
-               dlci->modem_tx = modem_tx;
-               gsmtty_modem_update(dlci, 0);
-       }
-}
-
-static const struct tty_port_operations gsm_port_ops = {
-       .carrier_raised = gsm_carrier_raised,
-       .dtr_rts = gsm_dtr_rts,
-};
-
-
-static int gsmtty_open(struct tty_struct *tty, struct file *filp)
-{
-       struct gsm_mux *gsm;
-       struct gsm_dlci *dlci;
-       struct tty_port *port;
-       unsigned int line = tty->index;
-       unsigned int mux = line >> 6;
-
-       line = line & 0x3F;
-
-       if (mux >= MAX_MUX)
-               return -ENXIO;
-       /* FIXME: we need to lock gsm_mux for lifetimes of ttys eventually */
-       if (gsm_mux[mux] == NULL)
-               return -EUNATCH;
-       if (line == 0 || line > 61)     /* 62/63 reserved */
-               return -ECHRNG;
-       gsm = gsm_mux[mux];
-       if (gsm->dead)
-               return -EL2HLT;
-       dlci = gsm->dlci[line];
-       if (dlci == NULL)
-               dlci = gsm_dlci_alloc(gsm, line);
-       if (dlci == NULL)
-               return -ENOMEM;
-       port = &dlci->port;
-       port->count++;
-       tty->driver_data = dlci;
-       tty_port_tty_set(port, tty);
-
-       dlci->modem_rx = 0;
-       /* We could in theory open and close before we wait - eg if we get
-          a DM straight back. This is ok as that will have caused a hangup */
-       set_bit(ASYNCB_INITIALIZED, &port->flags);
-       /* Start sending off SABM messages */
-       gsm_dlci_begin_open(dlci);
-       /* And wait for virtual carrier */
-       return tty_port_block_til_ready(port, tty, filp);
-}
-
-static void gsmtty_close(struct tty_struct *tty, struct file *filp)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       if (dlci == NULL)
-               return;
-       if (tty_port_close_start(&dlci->port, tty, filp) == 0)
-               return;
-       gsm_dlci_begin_close(dlci);
-       tty_port_close_end(&dlci->port, tty);
-       tty_port_tty_set(&dlci->port, NULL);
-}
-
-static void gsmtty_hangup(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       tty_port_hangup(&dlci->port);
-       gsm_dlci_begin_close(dlci);
-}
-
-static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf,
-                                                                   int len)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       /* Stuff the bytes into the fifo queue */
-       int sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock);
-       /* Need to kick the channel */
-       gsm_dlci_data_kick(dlci);
-       return sent;
-}
-
-static int gsmtty_write_room(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       return TX_SIZE - kfifo_len(dlci->fifo);
-}
-
-static int gsmtty_chars_in_buffer(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       return kfifo_len(dlci->fifo);
-}
-
-static void gsmtty_flush_buffer(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       /* Caution needed: If we implement reliable transport classes
-          then the data being transmitted can't simply be junked once
-          it has first hit the stack. Until then we can just blow it
-          away */
-       kfifo_reset(dlci->fifo);
-       /* Need to unhook this DLCI from the transmit queue logic */
-}
-
-static void gsmtty_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       /* The FIFO handles the queue so the kernel will do the right
-          thing waiting on chars_in_buffer before calling us. No work
-          to do here */
-}
-
-static int gsmtty_tiocmget(struct tty_struct *tty, struct file *filp)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       return dlci->modem_rx;
-}
-
-static int gsmtty_tiocmset(struct tty_struct *tty, struct file *filp,
-       unsigned int set, unsigned int clear)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       unsigned int modem_tx = dlci->modem_tx;
-
-       modem_tx &= clear;
-       modem_tx |= set;
-
-       if (modem_tx != dlci->modem_tx) {
-               dlci->modem_tx = modem_tx;
-               return gsmtty_modem_update(dlci, 0);
-       }
-       return 0;
-}
-
-
-static int gsmtty_ioctl(struct tty_struct *tty, struct file *filp,
-                       unsigned int cmd, unsigned long arg)
-{
-       return -ENOIOCTLCMD;
-}
-
-static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
-       /* For the moment its fixed. In actual fact the speed information
-          for the virtual channel can be propogated in both directions by
-          the RPN control message. This however rapidly gets nasty as we
-          then have to remap modem signals each way according to whether
-          our virtual cable is null modem etc .. */
-       tty_termios_copy_hw(tty->termios, old);
-}
-
-static void gsmtty_throttle(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       if (tty->termios->c_cflag & CRTSCTS)
-               dlci->modem_tx &= ~TIOCM_DTR;
-       dlci->throttled = 1;
-       /* Send an MSC with DTR cleared */
-       gsmtty_modem_update(dlci, 0);
-}
-
-static void gsmtty_unthrottle(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       if (tty->termios->c_cflag & CRTSCTS)
-               dlci->modem_tx |= TIOCM_DTR;
-       dlci->throttled = 0;
-       /* Send an MSC with DTR set */
-       gsmtty_modem_update(dlci, 0);
-}
-
-static int gsmtty_break_ctl(struct tty_struct *tty, int state)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       int encode = 0; /* Off */
-
-       if (state == -1)        /* "On indefinitely" - we can't encode this
-                                   properly */
-               encode = 0x0F;
-       else if (state > 0) {
-               encode = state / 200;   /* mS to encoding */
-               if (encode > 0x0F)
-                       encode = 0x0F;  /* Best effort */
-       }
-       return gsmtty_modem_update(dlci, encode);
-}
-
-static struct tty_driver *gsm_tty_driver;
-
-/* Virtual ttys for the demux */
-static const struct tty_operations gsmtty_ops = {
-       .open                   = gsmtty_open,
-       .close                  = gsmtty_close,
-       .write                  = gsmtty_write,
-       .write_room             = gsmtty_write_room,
-       .chars_in_buffer        = gsmtty_chars_in_buffer,
-       .flush_buffer           = gsmtty_flush_buffer,
-       .ioctl                  = gsmtty_ioctl,
-       .throttle               = gsmtty_throttle,
-       .unthrottle             = gsmtty_unthrottle,
-       .set_termios            = gsmtty_set_termios,
-       .hangup                 = gsmtty_hangup,
-       .wait_until_sent        = gsmtty_wait_until_sent,
-       .tiocmget               = gsmtty_tiocmget,
-       .tiocmset               = gsmtty_tiocmset,
-       .break_ctl              = gsmtty_break_ctl,
-};
-
-
-
-static int __init gsm_init(void)
-{
-       /* Fill in our line protocol discipline, and register it */
-       int status = tty_register_ldisc(N_GSM0710, &tty_ldisc_packet);
-       if (status != 0) {
-               printk(KERN_ERR "n_gsm: can't register line discipline (err = %d)\n", status);
-               return status;
-       }
-
-       gsm_tty_driver = alloc_tty_driver(256);
-       if (!gsm_tty_driver) {
-               tty_unregister_ldisc(N_GSM0710);
-               printk(KERN_ERR "gsm_init: tty allocation failed.\n");
-               return -EINVAL;
-       }
-       gsm_tty_driver->owner   = THIS_MODULE;
-       gsm_tty_driver->driver_name     = "gsmtty";
-       gsm_tty_driver->name            = "gsmtty";
-       gsm_tty_driver->major           = 0;    /* Dynamic */
-       gsm_tty_driver->minor_start     = 0;
-       gsm_tty_driver->type            = TTY_DRIVER_TYPE_SERIAL;
-       gsm_tty_driver->subtype = SERIAL_TYPE_NORMAL;
-       gsm_tty_driver->flags   = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
-                                                       | TTY_DRIVER_HARDWARE_BREAK;
-       gsm_tty_driver->init_termios    = tty_std_termios;
-       /* Fixme */
-       gsm_tty_driver->init_termios.c_lflag &= ~ECHO;
-       tty_set_operations(gsm_tty_driver, &gsmtty_ops);
-
-       spin_lock_init(&gsm_mux_lock);
-
-       if (tty_register_driver(gsm_tty_driver)) {
-               put_tty_driver(gsm_tty_driver);
-               tty_unregister_ldisc(N_GSM0710);
-               printk(KERN_ERR "gsm_init: tty registration failed.\n");
-               return -EBUSY;
-       }
-       printk(KERN_INFO "gsm_init: loaded as %d,%d.\n", gsm_tty_driver->major, gsm_tty_driver->minor_start);
-       return 0;
-}
-
-static void __exit gsm_exit(void)
-{
-       int status = tty_unregister_ldisc(N_GSM0710);
-       if (status != 0)
-               printk(KERN_ERR "n_gsm: can't unregister line discipline (err = %d)\n", status);
-       tty_unregister_driver(gsm_tty_driver);
-       put_tty_driver(gsm_tty_driver);
-       printk(KERN_INFO "gsm_init: unloaded.\n");
-}
-
-module_init(gsm_init);
-module_exit(gsm_exit);
-
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_LDISC(N_GSM0710);
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
deleted file mode 100644 (file)
index 47d3228..0000000
+++ /dev/null
@@ -1,1007 +0,0 @@
-/* generic HDLC line discipline for Linux
- *
- * Written by Paul Fulghum paulkf@microgate.com
- * for Microgate Corporation
- *
- * Microgate and SyncLink are registered trademarks of Microgate Corporation
- *
- * Adapted from ppp.c, written by Michael Callahan <callahan@maths.ox.ac.uk>,
- *     Al Longyear <longyear@netcom.com>,
- *     Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
- *
- * Original release 01/11/99
- *
- * This code is released under the GNU General Public License (GPL)
- *
- * This module implements the tty line discipline N_HDLC for use with
- * tty device drivers that support bit-synchronous HDLC communications.
- *
- * All HDLC data is frame oriented which means:
- *
- * 1. tty write calls represent one complete transmit frame of data
- *    The device driver should accept the complete frame or none of 
- *    the frame (busy) in the write method. Each write call should have
- *    a byte count in the range of 2-65535 bytes (2 is min HDLC frame
- *    with 1 addr byte and 1 ctrl byte). The max byte count of 65535
- *    should include any crc bytes required. For example, when using
- *    CCITT CRC32, 4 crc bytes are required, so the maximum size frame
- *    the application may transmit is limited to 65531 bytes. For CCITT
- *    CRC16, the maximum application frame size would be 65533.
- *
- *
- * 2. receive callbacks from the device driver represents
- *    one received frame. The device driver should bypass
- *    the tty flip buffer and call the line discipline receive
- *    callback directly to avoid fragmenting or concatenating
- *    multiple frames into a single receive callback.
- *
- *    The HDLC line discipline queues the receive frames in separate
- *    buffers so complete receive frames can be returned by the
- *    tty read calls.
- *
- * 3. tty read calls returns an entire frame of data or nothing.
- *    
- * 4. all send and receive data is considered raw. No processing
- *    or translation is performed by the line discipline, regardless
- *    of the tty flags
- *
- * 5. When line discipline is queried for the amount of receive
- *    data available (FIOC), 0 is returned if no data available,
- *    otherwise the count of the next available frame is returned.
- *    (instead of the sum of all received frame counts).
- *
- * These conventions allow the standard tty programming interface
- * to be used for synchronous HDLC applications when used with
- * this line discipline (or another line discipline that is frame
- * oriented such as N_PPP).
- *
- * The SyncLink driver (synclink.c) implements both asynchronous
- * (using standard line discipline N_TTY) and synchronous HDLC
- * (using N_HDLC) communications, with the latter using the above
- * conventions.
- *
- * This implementation is very basic and does not maintain
- * any statistics. The main point is to enforce the raw data
- * and frame orientation of HDLC communications.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define HDLC_MAGIC 0x239e
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-
-#undef VERSION
-#define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
-
-#include <linux/poll.h>
-#include <linux/in.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/smp_lock.h>
-#include <linux/string.h>      /* used in new tty drivers */
-#include <linux/signal.h>      /* used in new tty drivers */
-#include <linux/if.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/termios.h>
-#include <asm/uaccess.h>
-
-/*
- * Buffers for individual HDLC frames
- */
-#define MAX_HDLC_FRAME_SIZE 65535 
-#define DEFAULT_RX_BUF_COUNT 10
-#define MAX_RX_BUF_COUNT 60
-#define DEFAULT_TX_BUF_COUNT 3
-
-struct n_hdlc_buf {
-       struct n_hdlc_buf *link;
-       int               count;
-       char              buf[1];
-};
-
-#define        N_HDLC_BUF_SIZE (sizeof(struct n_hdlc_buf) + maxframe)
-
-struct n_hdlc_buf_list {
-       struct n_hdlc_buf *head;
-       struct n_hdlc_buf *tail;
-       int               count;
-       spinlock_t        spinlock;
-};
-
-/**
- * struct n_hdlc - per device instance data structure
- * @magic - magic value for structure
- * @flags - miscellaneous control flags
- * @tty - ptr to TTY structure
- * @backup_tty - TTY to use if tty gets closed
- * @tbusy - reentrancy flag for tx wakeup code
- * @woke_up - FIXME: describe this field
- * @tbuf - currently transmitting tx buffer
- * @tx_buf_list - list of pending transmit frame buffers
- * @rx_buf_list - list of received frame buffers
- * @tx_free_buf_list - list unused transmit frame buffers
- * @rx_free_buf_list - list unused received frame buffers
- */
-struct n_hdlc {
-       int                     magic;
-       __u32                   flags;
-       struct tty_struct       *tty;
-       struct tty_struct       *backup_tty;
-       int                     tbusy;
-       int                     woke_up;
-       struct n_hdlc_buf       *tbuf;
-       struct n_hdlc_buf_list  tx_buf_list;
-       struct n_hdlc_buf_list  rx_buf_list;
-       struct n_hdlc_buf_list  tx_free_buf_list;
-       struct n_hdlc_buf_list  rx_free_buf_list;
-};
-
-/*
- * HDLC buffer list manipulation functions
- */
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list);
-static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
-                          struct n_hdlc_buf *buf);
-static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
-
-/* Local functions */
-
-static struct n_hdlc *n_hdlc_alloc (void);
-
-/* debug level can be set by insmod for debugging purposes */
-#define DEBUG_LEVEL_INFO       1
-static int debuglevel;
-
-/* max frame size for memory allocations */
-static int maxframe = 4096;
-
-/* TTY callbacks */
-
-static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
-                          __u8 __user *buf, size_t nr);
-static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
-                           const unsigned char *buf, size_t nr);
-static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
-                           unsigned int cmd, unsigned long arg);
-static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
-                                   poll_table *wait);
-static int n_hdlc_tty_open(struct tty_struct *tty);
-static void n_hdlc_tty_close(struct tty_struct *tty);
-static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp,
-                              char *fp, int count);
-static void n_hdlc_tty_wakeup(struct tty_struct *tty);
-
-#define bset(p,b)      ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
-
-#define tty2n_hdlc(tty)        ((struct n_hdlc *) ((tty)->disc_data))
-#define n_hdlc2tty(n_hdlc)     ((n_hdlc)->tty)
-
-static void flush_rx_queue(struct tty_struct *tty)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-       struct n_hdlc_buf *buf;
-
-       while ((buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list)))
-               n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, buf);
-}
-
-static void flush_tx_queue(struct tty_struct *tty)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-       struct n_hdlc_buf *buf;
-       unsigned long flags;
-
-       while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
-               n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
-       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
-       if (n_hdlc->tbuf) {
-               n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf);
-               n_hdlc->tbuf = NULL;
-       }
-       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
-}
-
-static struct tty_ldisc_ops n_hdlc_ldisc = {
-       .owner          = THIS_MODULE,
-       .magic          = TTY_LDISC_MAGIC,
-       .name           = "hdlc",
-       .open           = n_hdlc_tty_open,
-       .close          = n_hdlc_tty_close,
-       .read           = n_hdlc_tty_read,
-       .write          = n_hdlc_tty_write,
-       .ioctl          = n_hdlc_tty_ioctl,
-       .poll           = n_hdlc_tty_poll,
-       .receive_buf    = n_hdlc_tty_receive,
-       .write_wakeup   = n_hdlc_tty_wakeup,
-       .flush_buffer   = flush_rx_queue,
-};
-
-/**
- * n_hdlc_release - release an n_hdlc per device line discipline info structure
- * @n_hdlc - per device line discipline info structure
- */
-static void n_hdlc_release(struct n_hdlc *n_hdlc)
-{
-       struct tty_struct *tty = n_hdlc2tty (n_hdlc);
-       struct n_hdlc_buf *buf;
-       
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__);
-               
-       /* Ensure that the n_hdlcd process is not hanging on select()/poll() */
-       wake_up_interruptible (&tty->read_wait);
-       wake_up_interruptible (&tty->write_wait);
-
-       if (tty->disc_data == n_hdlc)
-               tty->disc_data = NULL;  /* Break the tty->n_hdlc link */
-
-       /* Release transmit and receive buffers */
-       for(;;) {
-               buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
-               if (buf) {
-                       kfree(buf);
-               } else
-                       break;
-       }
-       for(;;) {
-               buf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
-               if (buf) {
-                       kfree(buf);
-               } else
-                       break;
-       }
-       for(;;) {
-               buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
-               if (buf) {
-                       kfree(buf);
-               } else
-                       break;
-       }
-       for(;;) {
-               buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
-               if (buf) {
-                       kfree(buf);
-               } else
-                       break;
-       }
-       kfree(n_hdlc->tbuf);
-       kfree(n_hdlc);
-       
-}      /* end of n_hdlc_release() */
-
-/**
- * n_hdlc_tty_close - line discipline close
- * @tty - pointer to tty info structure
- *
- * Called when the line discipline is changed to something
- * else, the tty is closed, or the tty detects a hangup.
- */
-static void n_hdlc_tty_close(struct tty_struct *tty)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_close() called\n",__FILE__,__LINE__);
-               
-       if (n_hdlc != NULL) {
-               if (n_hdlc->magic != HDLC_MAGIC) {
-                       printk (KERN_WARNING"n_hdlc: trying to close unopened tty!\n");
-                       return;
-               }
-#if defined(TTY_NO_WRITE_SPLIT)
-               clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
-#endif
-               tty->disc_data = NULL;
-               if (tty == n_hdlc->backup_tty)
-                       n_hdlc->backup_tty = NULL;
-               if (tty != n_hdlc->tty)
-                       return;
-               if (n_hdlc->backup_tty) {
-                       n_hdlc->tty = n_hdlc->backup_tty;
-               } else {
-                       n_hdlc_release (n_hdlc);
-               }
-       }
-       
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_close() success\n",__FILE__,__LINE__);
-               
-}      /* end of n_hdlc_tty_close() */
-
-/**
- * n_hdlc_tty_open - called when line discipline changed to n_hdlc
- * @tty - pointer to tty info structure
- *
- * Returns 0 if success, otherwise error code
- */
-static int n_hdlc_tty_open (struct tty_struct *tty)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_open() called (device=%s)\n",
-               __FILE__,__LINE__,
-               tty->name);
-               
-       /* There should not be an existing table for this slot. */
-       if (n_hdlc) {
-               printk (KERN_ERR"n_hdlc_tty_open:tty already associated!\n" );
-               return -EEXIST;
-       }
-       
-       n_hdlc = n_hdlc_alloc();
-       if (!n_hdlc) {
-               printk (KERN_ERR "n_hdlc_alloc failed\n");
-               return -ENFILE;
-       }
-               
-       tty->disc_data = n_hdlc;
-       n_hdlc->tty    = tty;
-       tty->receive_room = 65536;
-       
-#if defined(TTY_NO_WRITE_SPLIT)
-       /* change tty_io write() to not split large writes into 8K chunks */
-       set_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
-#endif
-       
-       /* flush receive data from driver */
-       tty_driver_flush_buffer(tty);
-               
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__);
-               
-       return 0;
-       
-}      /* end of n_tty_hdlc_open() */
-
-/**
- * n_hdlc_send_frames - send frames on pending send buffer list
- * @n_hdlc - pointer to ldisc instance data
- * @tty - pointer to tty instance data
- *
- * Send frames on pending send buffer list until the driver does not accept a
- * frame (busy) this function is called after adding a frame to the send buffer
- * list and by the tty wakeup callback.
- */
-static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
-{
-       register int actual;
-       unsigned long flags;
-       struct n_hdlc_buf *tbuf;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__);
- check_again:
-               
-       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
-       if (n_hdlc->tbusy) {
-               n_hdlc->woke_up = 1;
-               spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
-               return;
-       }
-       n_hdlc->tbusy = 1;
-       n_hdlc->woke_up = 0;
-       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
-
-       /* get current transmit buffer or get new transmit */
-       /* buffer from list of pending transmit buffers */
-               
-       tbuf = n_hdlc->tbuf;
-       if (!tbuf)
-               tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
-               
-       while (tbuf) {
-               if (debuglevel >= DEBUG_LEVEL_INFO)     
-                       printk("%s(%d)sending frame %p, count=%d\n",
-                               __FILE__,__LINE__,tbuf,tbuf->count);
-                       
-               /* Send the next block of data to device */
-               tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-               actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
-
-               /* rollback was possible and has been done */
-               if (actual == -ERESTARTSYS) {
-                       n_hdlc->tbuf = tbuf;
-                       break;
-               }
-               /* if transmit error, throw frame away by */
-               /* pretending it was accepted by driver */
-               if (actual < 0)
-                       actual = tbuf->count;
-               
-               if (actual == tbuf->count) {
-                       if (debuglevel >= DEBUG_LEVEL_INFO)     
-                               printk("%s(%d)frame %p completed\n",
-                                       __FILE__,__LINE__,tbuf);
-                                       
-                       /* free current transmit buffer */
-                       n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf);
-                       
-                       /* this tx buffer is done */
-                       n_hdlc->tbuf = NULL;
-                       
-                       /* wait up sleeping writers */
-                       wake_up_interruptible(&tty->write_wait);
-       
-                       /* get next pending transmit buffer */
-                       tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
-               } else {
-                       if (debuglevel >= DEBUG_LEVEL_INFO)     
-                               printk("%s(%d)frame %p pending\n",
-                                       __FILE__,__LINE__,tbuf);
-                                       
-                       /* buffer not accepted by driver */
-                       /* set this buffer as pending buffer */
-                       n_hdlc->tbuf = tbuf;
-                       break;
-               }
-       }
-       
-       if (!tbuf)
-               tty->flags  &= ~(1 << TTY_DO_WRITE_WAKEUP);
-       
-       /* Clear the re-entry flag */
-       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
-       n_hdlc->tbusy = 0;
-       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); 
-       
-        if (n_hdlc->woke_up)
-         goto check_again;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_send_frames() exit\n",__FILE__,__LINE__);
-               
-}      /* end of n_hdlc_send_frames() */
-
-/**
- * n_hdlc_tty_wakeup - Callback for transmit wakeup
- * @tty        - pointer to associated tty instance data
- *
- * Called when low level device driver can accept more send data.
- */
-static void n_hdlc_tty_wakeup(struct tty_struct *tty)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_wakeup() called\n",__FILE__,__LINE__);
-               
-       if (!n_hdlc)
-               return;
-
-       if (tty != n_hdlc->tty) {
-               tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-               return;
-       }
-
-       n_hdlc_send_frames (n_hdlc, tty);
-               
-}      /* end of n_hdlc_tty_wakeup() */
-
-/**
- * n_hdlc_tty_receive - Called by tty driver when receive data is available
- * @tty        - pointer to tty instance data
- * @data - pointer to received data
- * @flags - pointer to flags for data
- * @count - count of received data in bytes
- *
- * Called by tty low level driver when receive data is available. Data is
- * interpreted as one HDLC frame.
- */
-static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
-                              char *flags, int count)
-{
-       register struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-       register struct n_hdlc_buf *buf;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_receive() called count=%d\n",
-                       __FILE__,__LINE__, count);
-               
-       /* This can happen if stuff comes in on the backup tty */
-       if (!n_hdlc || tty != n_hdlc->tty)
-               return;
-               
-       /* verify line is using HDLC discipline */
-       if (n_hdlc->magic != HDLC_MAGIC) {
-               printk("%s(%d) line not using HDLC discipline\n",
-                       __FILE__,__LINE__);
-               return;
-       }
-       
-       if ( count>maxframe ) {
-               if (debuglevel >= DEBUG_LEVEL_INFO)     
-                       printk("%s(%d) rx count>maxframesize, data discarded\n",
-                              __FILE__,__LINE__);
-               return;
-       }
-
-       /* get a free HDLC buffer */    
-       buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
-       if (!buf) {
-               /* no buffers in free list, attempt to allocate another rx buffer */
-               /* unless the maximum count has been reached */
-               if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT)
-                       buf = kmalloc(N_HDLC_BUF_SIZE, GFP_ATOMIC);
-       }
-       
-       if (!buf) {
-               if (debuglevel >= DEBUG_LEVEL_INFO)     
-                       printk("%s(%d) no more rx buffers, data discarded\n",
-                              __FILE__,__LINE__);
-               return;
-       }
-               
-       /* copy received data to HDLC buffer */
-       memcpy(buf->buf,data,count);
-       buf->count=count;
-
-       /* add HDLC buffer to list of received frames */
-       n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf);
-       
-       /* wake up any blocked reads and perform async signalling */
-       wake_up_interruptible (&tty->read_wait);
-       if (n_hdlc->tty->fasync != NULL)
-               kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN);
-
-}      /* end of n_hdlc_tty_receive() */
-
-/**
- * n_hdlc_tty_read - Called to retrieve one frame of data (if available)
- * @tty - pointer to tty instance data
- * @file - pointer to open file object
- * @buf - pointer to returned data buffer
- * @nr - size of returned data buffer
- *     
- * Returns the number of bytes returned or error code.
- */
-static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
-                          __u8 __user *buf, size_t nr)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-       int ret;
-       struct n_hdlc_buf *rbuf;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__);
-               
-       /* Validate the pointers */
-       if (!n_hdlc)
-               return -EIO;
-
-       /* verify user access to buffer */
-       if (!access_ok(VERIFY_WRITE, buf, nr)) {
-               printk(KERN_WARNING "%s(%d) n_hdlc_tty_read() can't verify user "
-               "buffer\n", __FILE__, __LINE__);
-               return -EFAULT;
-       }
-
-       tty_lock();
-
-       for (;;) {
-               if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
-                       tty_unlock();
-                       return -EIO;
-               }
-
-               n_hdlc = tty2n_hdlc (tty);
-               if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||
-                        tty != n_hdlc->tty) {
-                       tty_unlock();
-                       return 0;
-               }
-
-               rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
-               if (rbuf)
-                       break;
-                       
-               /* no data */
-               if (file->f_flags & O_NONBLOCK) {
-                       tty_unlock();
-                       return -EAGAIN;
-               }
-                       
-               interruptible_sleep_on (&tty->read_wait);
-               if (signal_pending(current)) {
-                       tty_unlock();
-                       return -EINTR;
-               }
-       }
-               
-       if (rbuf->count > nr)
-               /* frame too large for caller's buffer (discard frame) */
-               ret = -EOVERFLOW;
-       else {
-               /* Copy the data to the caller's buffer */
-               if (copy_to_user(buf, rbuf->buf, rbuf->count))
-                       ret = -EFAULT;
-               else
-                       ret = rbuf->count;
-       }
-       
-       /* return HDLC buffer to free list unless the free list */
-       /* count has exceeded the default value, in which case the */
-       /* buffer is freed back to the OS to conserve memory */
-       if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT)
-               kfree(rbuf);
-       else    
-               n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf);
-       tty_unlock();
-       return ret;
-       
-}      /* end of n_hdlc_tty_read() */
-
-/**
- * n_hdlc_tty_write - write a single frame of data to device
- * @tty        - pointer to associated tty device instance data
- * @file - pointer to file object data
- * @data - pointer to transmit data (one frame)
- * @count - size of transmit frame in bytes
- *             
- * Returns the number of bytes written (or error code).
- */
-static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
-                           const unsigned char *data, size_t count)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-       int error = 0;
-       DECLARE_WAITQUEUE(wait, current);
-       struct n_hdlc_buf *tbuf;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_write() called count=%Zd\n",
-                       __FILE__,__LINE__,count);
-               
-       /* Verify pointers */
-       if (!n_hdlc)
-               return -EIO;
-
-       if (n_hdlc->magic != HDLC_MAGIC)
-               return -EIO;
-
-       /* verify frame size */
-       if (count > maxframe ) {
-               if (debuglevel & DEBUG_LEVEL_INFO)
-                       printk (KERN_WARNING
-                               "n_hdlc_tty_write: truncating user packet "
-                               "from %lu to %d\n", (unsigned long) count,
-                               maxframe );
-               count = maxframe;
-       }
-       
-       tty_lock();
-
-       add_wait_queue(&tty->write_wait, &wait);
-       set_current_state(TASK_INTERRUPTIBLE);
-       
-       /* Allocate transmit buffer */
-       /* sleep until transmit buffer available */             
-       while (!(tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list))) {
-               if (file->f_flags & O_NONBLOCK) {
-                       error = -EAGAIN;
-                       break;
-               }
-               schedule();
-                       
-               n_hdlc = tty2n_hdlc (tty);
-               if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || 
-                   tty != n_hdlc->tty) {
-                       printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc);
-                       error = -EIO;
-                       break;
-               }
-                       
-               if (signal_pending(current)) {
-                       error = -EINTR;
-                       break;
-               }
-       }
-
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&tty->write_wait, &wait);
-
-       if (!error) {           
-               /* Retrieve the user's buffer */
-               memcpy(tbuf->buf, data, count);
-
-               /* Send the data */
-               tbuf->count = error = count;
-               n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf);
-               n_hdlc_send_frames(n_hdlc,tty);
-       }
-       tty_unlock();
-       return error;
-       
-}      /* end of n_hdlc_tty_write() */
-
-/**
- * n_hdlc_tty_ioctl - process IOCTL system call for the tty device.
- * @tty - pointer to tty instance data
- * @file - pointer to open file object for device
- * @cmd - IOCTL command code
- * @arg - argument for IOCTL call (cmd dependent)
- *
- * Returns command dependent result.
- */
-static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
-                           unsigned int cmd, unsigned long arg)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-       int error = 0;
-       int count;
-       unsigned long flags;
-       
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
-                       __FILE__,__LINE__,cmd);
-               
-       /* Verify the status of the device */
-       if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC)
-               return -EBADF;
-
-       switch (cmd) {
-       case FIONREAD:
-               /* report count of read data available */
-               /* in next available frame (if any) */
-               spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
-               if (n_hdlc->rx_buf_list.head)
-                       count = n_hdlc->rx_buf_list.head->count;
-               else
-                       count = 0;
-               spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
-               error = put_user(count, (int __user *)arg);
-               break;
-
-       case TIOCOUTQ:
-               /* get the pending tx byte count in the driver */
-               count = tty_chars_in_buffer(tty);
-               /* add size of next output frame in queue */
-               spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
-               if (n_hdlc->tx_buf_list.head)
-                       count += n_hdlc->tx_buf_list.head->count;
-               spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
-               error = put_user(count, (int __user *)arg);
-               break;
-
-       case TCFLSH:
-               switch (arg) {
-               case TCIOFLUSH:
-               case TCOFLUSH:
-                       flush_tx_queue(tty);
-               }
-               /* fall through to default */
-
-       default:
-               error = n_tty_ioctl_helper(tty, file, cmd, arg);
-               break;
-       }
-       return error;
-       
-}      /* end of n_hdlc_tty_ioctl() */
-
-/**
- * n_hdlc_tty_poll - TTY callback for poll system call
- * @tty - pointer to tty instance data
- * @filp - pointer to open file object for device
- * @poll_table - wait queue for operations
- * 
- * Determine which operations (read/write) will not block and return info
- * to caller.
- * Returns a bit mask containing info on which ops will not block.
- */
-static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
-                                   poll_table *wait)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-       unsigned int mask = 0;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_poll() called\n",__FILE__,__LINE__);
-               
-       if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) {
-               /* queue current process into any wait queue that */
-               /* may awaken in the future (read and write) */
-
-               poll_wait(filp, &tty->read_wait, wait);
-               poll_wait(filp, &tty->write_wait, wait);
-
-               /* set bits for operations that won't block */
-               if (n_hdlc->rx_buf_list.head)
-                       mask |= POLLIN | POLLRDNORM;    /* readable */
-               if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
-                       mask |= POLLHUP;
-               if (tty_hung_up_p(filp))
-                       mask |= POLLHUP;
-               if (!tty_is_writelocked(tty) &&
-                               n_hdlc->tx_free_buf_list.head)
-                       mask |= POLLOUT | POLLWRNORM;   /* writable */
-       }
-       return mask;
-}      /* end of n_hdlc_tty_poll() */
-
-/**
- * n_hdlc_alloc - allocate an n_hdlc instance data structure
- *
- * Returns a pointer to newly created structure if success, otherwise %NULL
- */
-static struct n_hdlc *n_hdlc_alloc(void)
-{
-       struct n_hdlc_buf *buf;
-       int i;
-       struct n_hdlc *n_hdlc = kmalloc(sizeof(*n_hdlc), GFP_KERNEL);
-
-       if (!n_hdlc)
-               return NULL;
-
-       memset(n_hdlc, 0, sizeof(*n_hdlc));
-
-       n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);
-       n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);
-       n_hdlc_buf_list_init(&n_hdlc->rx_buf_list);
-       n_hdlc_buf_list_init(&n_hdlc->tx_buf_list);
-       
-       /* allocate free rx buffer list */
-       for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
-               buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
-               if (buf)
-                       n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,buf);
-               else if (debuglevel >= DEBUG_LEVEL_INFO)        
-                       printk("%s(%d)n_hdlc_alloc(), kalloc() failed for rx buffer %d\n",__FILE__,__LINE__, i);
-       }
-       
-       /* allocate free tx buffer list */
-       for(i=0;i<DEFAULT_TX_BUF_COUNT;i++) {
-               buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
-               if (buf)
-                       n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,buf);
-               else if (debuglevel >= DEBUG_LEVEL_INFO)        
-                       printk("%s(%d)n_hdlc_alloc(), kalloc() failed for tx buffer %d\n",__FILE__,__LINE__, i);
-       }
-       
-       /* Initialize the control block */
-       n_hdlc->magic  = HDLC_MAGIC;
-       n_hdlc->flags  = 0;
-       
-       return n_hdlc;
-       
-}      /* end of n_hdlc_alloc() */
-
-/**
- * n_hdlc_buf_list_init - initialize specified HDLC buffer list
- * @list - pointer to buffer list
- */
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list)
-{
-       memset(list, 0, sizeof(*list));
-       spin_lock_init(&list->spinlock);
-}      /* end of n_hdlc_buf_list_init() */
-
-/**
- * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
- * @list - pointer to buffer list
- * @buf        - pointer to buffer
- */
-static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
-                          struct n_hdlc_buf *buf)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&list->spinlock,flags);
-       
-       buf->link=NULL;
-       if (list->tail)
-               list->tail->link = buf;
-       else
-               list->head = buf;
-       list->tail = buf;
-       (list->count)++;
-       
-       spin_unlock_irqrestore(&list->spinlock,flags);
-       
-}      /* end of n_hdlc_buf_put() */
-
-/**
- * n_hdlc_buf_get - remove and return an HDLC buffer from list
- * @list - pointer to HDLC buffer list
- * 
- * Remove and return an HDLC buffer from the head of the specified HDLC buffer
- * list.
- * Returns a pointer to HDLC buffer if available, otherwise %NULL.
- */
-static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list)
-{
-       unsigned long flags;
-       struct n_hdlc_buf *buf;
-       spin_lock_irqsave(&list->spinlock,flags);
-       
-       buf = list->head;
-       if (buf) {
-               list->head = buf->link;
-               (list->count)--;
-       }
-       if (!list->head)
-               list->tail = NULL;
-       
-       spin_unlock_irqrestore(&list->spinlock,flags);
-       return buf;
-       
-}      /* end of n_hdlc_buf_get() */
-
-static char hdlc_banner[] __initdata =
-       KERN_INFO "HDLC line discipline maxframe=%u\n";
-static char hdlc_register_ok[] __initdata =
-       KERN_INFO "N_HDLC line discipline registered.\n";
-static char hdlc_register_fail[] __initdata =
-       KERN_ERR "error registering line discipline: %d\n";
-static char hdlc_init_fail[] __initdata =
-       KERN_INFO "N_HDLC: init failure %d\n";
-
-static int __init n_hdlc_init(void)
-{
-       int status;
-
-       /* range check maxframe arg */
-       if (maxframe < 4096)
-               maxframe = 4096;
-       else if (maxframe > 65535)
-               maxframe = 65535;
-
-       printk(hdlc_banner, maxframe);
-
-       status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc);
-       if (!status)
-               printk(hdlc_register_ok);
-       else
-               printk(hdlc_register_fail, status);
-
-       if (status)
-               printk(hdlc_init_fail, status);
-       return status;
-       
-}      /* end of init_module() */
-
-static char hdlc_unregister_ok[] __exitdata =
-       KERN_INFO "N_HDLC: line discipline unregistered\n";
-static char hdlc_unregister_fail[] __exitdata =
-       KERN_ERR "N_HDLC: can't unregister line discipline (err = %d)\n";
-
-static void __exit n_hdlc_exit(void)
-{
-       /* Release tty registration of line discipline */
-       int status = tty_unregister_ldisc(N_HDLC);
-
-       if (status)
-               printk(hdlc_unregister_fail, status);
-       else
-               printk(hdlc_unregister_ok);
-}
-
-module_init(n_hdlc_init);
-module_exit(n_hdlc_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com");
-module_param(debuglevel, int, 0);
-module_param(maxframe, int, 0);
-MODULE_ALIAS_LDISC(N_HDLC);
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
deleted file mode 100644 (file)
index 88dda0c..0000000
+++ /dev/null
@@ -1,1264 +0,0 @@
-/* r3964 linediscipline for linux
- *
- * -----------------------------------------------------------
- * Copyright by 
- * Philips Automation Projects
- * Kassel (Germany)
- * -----------------------------------------------------------
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- *
- * Author:
- * L. Haag
- *
- * $Log: n_r3964.c,v $
- * Revision 1.10  2001/03/18 13:02:24  dwmw2
- * Fix timer usage, use spinlocks properly.
- *
- * Revision 1.9  2001/03/18 12:52:14  dwmw2
- * Merge changes in 2.4.2
- *
- * Revision 1.8  2000/03/23 14:14:54  dwmw2
- * Fix race in sleeping in r3964_read()
- *
- * Revision 1.7  1999/28/08 11:41:50  dwmw2
- * Port to 2.3 kernel
- *
- * Revision 1.6  1998/09/30 00:40:40  dwmw2
- * Fixed compilation on 2.0.x kernels
- * Updated to newly registered tty-ldisc number 9
- *
- * Revision 1.5  1998/09/04 21:57:36  dwmw2
- * Signal handling bug fixes, port to 2.1.x.
- *
- * Revision 1.4  1998/04/02 20:26:59  lhaag
- * select, blocking, ...
- *
- * Revision 1.3  1998/02/12 18:58:43  root
- * fixed some memory leaks
- * calculation of checksum characters
- *
- * Revision 1.2  1998/02/07 13:03:34  root
- * ioctl read_telegram
- *
- * Revision 1.1  1998/02/06 19:21:03  root
- * Initial revision
- *
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/string.h>      /* used in new tty drivers */
-#include <linux/signal.h>      /* used in new tty drivers */
-#include <linux/ioctl.h>
-#include <linux/n_r3964.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-
-/*#define DEBUG_QUEUE*/
-
-/* Log successful handshake and protocol operations  */
-/*#define DEBUG_PROTO_S*/
-
-/* Log handshake and protocol errors: */
-/*#define DEBUG_PROTO_E*/
-
-/* Log Linediscipline operations (open, close, read, write...): */
-/*#define DEBUG_LDISC*/
-
-/* Log module and memory operations (init, cleanup; kmalloc, kfree): */
-/*#define DEBUG_MODUL*/
-
-/* Macro helpers for debug output: */
-#define TRACE(format, args...) printk("r3964: " format "\n" , ## args)
-
-#ifdef DEBUG_MODUL
-#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_M(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_PROTO_S
-#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_PS(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_PROTO_E
-#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_PE(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_LDISC
-#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_L(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_QUEUE
-#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_Q(fmt, arg...) do {} while (0)
-#endif
-static void add_tx_queue(struct r3964_info *, struct r3964_block_header *);
-static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code);
-static void put_char(struct r3964_info *pInfo, unsigned char ch);
-static void trigger_transmit(struct r3964_info *pInfo);
-static void retry_transmit(struct r3964_info *pInfo);
-static void transmit_block(struct r3964_info *pInfo);
-static void receive_char(struct r3964_info *pInfo, const unsigned char c);
-static void receive_error(struct r3964_info *pInfo, const char flag);
-static void on_timeout(unsigned long priv);
-static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg);
-static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
-               unsigned char __user * buf);
-static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
-               int error_code, struct r3964_block_header *pBlock);
-static struct r3964_message *remove_msg(struct r3964_info *pInfo,
-               struct r3964_client_info *pClient);
-static void remove_client_block(struct r3964_info *pInfo,
-               struct r3964_client_info *pClient);
-
-static int r3964_open(struct tty_struct *tty);
-static void r3964_close(struct tty_struct *tty);
-static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
-               unsigned char __user * buf, size_t nr);
-static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
-               const unsigned char *buf, size_t nr);
-static int r3964_ioctl(struct tty_struct *tty, struct file *file,
-               unsigned int cmd, unsigned long arg);
-static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);
-static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
-               struct poll_table_struct *wait);
-static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-               char *fp, int count);
-
-static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
-       .owner = THIS_MODULE,
-       .magic = TTY_LDISC_MAGIC,
-       .name = "R3964",
-       .open = r3964_open,
-       .close = r3964_close,
-       .read = r3964_read,
-       .write = r3964_write,
-       .ioctl = r3964_ioctl,
-       .set_termios = r3964_set_termios,
-       .poll = r3964_poll,
-       .receive_buf = r3964_receive_buf,
-};
-
-static void dump_block(const unsigned char *block, unsigned int length)
-{
-       unsigned int i, j;
-       char linebuf[16 * 3 + 1];
-
-       for (i = 0; i < length; i += 16) {
-               for (j = 0; (j < 16) && (j + i < length); j++) {
-                       sprintf(linebuf + 3 * j, "%02x ", block[i + j]);
-               }
-               linebuf[3 * j] = '\0';
-               TRACE_PS("%s", linebuf);
-       }
-}
-
-/*************************************************************
- * Driver initialisation
- *************************************************************/
-
-/*************************************************************
- * Module support routines
- *************************************************************/
-
-static void __exit r3964_exit(void)
-{
-       int status;
-
-       TRACE_M("cleanup_module()");
-
-       status = tty_unregister_ldisc(N_R3964);
-
-       if (status != 0) {
-               printk(KERN_ERR "r3964: error unregistering linediscipline: "
-                               "%d\n", status);
-       } else {
-               TRACE_L("linediscipline successfully unregistered");
-       }
-}
-
-static int __init r3964_init(void)
-{
-       int status;
-
-       printk("r3964: Philips r3964 Driver $Revision: 1.10 $\n");
-
-       /*
-        * Register the tty line discipline
-        */
-
-       status = tty_register_ldisc(N_R3964, &tty_ldisc_N_R3964);
-       if (status == 0) {
-               TRACE_L("line discipline %d registered", N_R3964);
-               TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags,
-                       tty_ldisc_N_R3964.num);
-               TRACE_L("open=%p", tty_ldisc_N_R3964.open);
-               TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964);
-       } else {
-               printk(KERN_ERR "r3964: error registering line discipline: "
-                               "%d\n", status);
-       }
-       return status;
-}
-
-module_init(r3964_init);
-module_exit(r3964_exit);
-
-/*************************************************************
- * Protocol implementation routines
- *************************************************************/
-
-static void add_tx_queue(struct r3964_info *pInfo,
-                        struct r3964_block_header *pHeader)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&pInfo->lock, flags);
-
-       pHeader->next = NULL;
-
-       if (pInfo->tx_last == NULL) {
-               pInfo->tx_first = pInfo->tx_last = pHeader;
-       } else {
-               pInfo->tx_last->next = pHeader;
-               pInfo->tx_last = pHeader;
-       }
-
-       spin_unlock_irqrestore(&pInfo->lock, flags);
-
-       TRACE_Q("add_tx_queue %p, length %d, tx_first = %p",
-               pHeader, pHeader->length, pInfo->tx_first);
-}
-
-static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code)
-{
-       struct r3964_block_header *pHeader;
-       unsigned long flags;
-#ifdef DEBUG_QUEUE
-       struct r3964_block_header *pDump;
-#endif
-
-       pHeader = pInfo->tx_first;
-
-       if (pHeader == NULL)
-               return;
-
-#ifdef DEBUG_QUEUE
-       printk("r3964: remove_from_tx_queue: %p, length %u - ",
-               pHeader, pHeader->length);
-       for (pDump = pHeader; pDump; pDump = pDump->next)
-               printk("%p ", pDump);
-       printk("\n");
-#endif
-
-       if (pHeader->owner) {
-               if (error_code) {
-                       add_msg(pHeader->owner, R3964_MSG_ACK, 0,
-                               error_code, NULL);
-               } else {
-                       add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,
-                               error_code, NULL);
-               }
-               wake_up_interruptible(&pInfo->read_wait);
-       }
-
-       spin_lock_irqsave(&pInfo->lock, flags);
-
-       pInfo->tx_first = pHeader->next;
-       if (pInfo->tx_first == NULL) {
-               pInfo->tx_last = NULL;
-       }
-
-       spin_unlock_irqrestore(&pInfo->lock, flags);
-
-       kfree(pHeader);
-       TRACE_M("remove_from_tx_queue - kfree %p", pHeader);
-
-       TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p",
-               pInfo->tx_first, pInfo->tx_last);
-}
-
-static void add_rx_queue(struct r3964_info *pInfo,
-                        struct r3964_block_header *pHeader)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&pInfo->lock, flags);
-
-       pHeader->next = NULL;
-
-       if (pInfo->rx_last == NULL) {
-               pInfo->rx_first = pInfo->rx_last = pHeader;
-       } else {
-               pInfo->rx_last->next = pHeader;
-               pInfo->rx_last = pHeader;
-       }
-       pInfo->blocks_in_rx_queue++;
-
-       spin_unlock_irqrestore(&pInfo->lock, flags);
-
-       TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d",
-               pHeader, pHeader->length,
-               pInfo->rx_first, pInfo->blocks_in_rx_queue);
-}
-
-static void remove_from_rx_queue(struct r3964_info *pInfo,
-                                struct r3964_block_header *pHeader)
-{
-       unsigned long flags;
-       struct r3964_block_header *pFind;
-
-       if (pHeader == NULL)
-               return;
-
-       TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
-               pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
-       TRACE_Q("remove_from_rx_queue: %p, length %u",
-               pHeader, pHeader->length);
-
-       spin_lock_irqsave(&pInfo->lock, flags);
-
-       if (pInfo->rx_first == pHeader) {
-               /* Remove the first block in the linked list: */
-               pInfo->rx_first = pHeader->next;
-
-               if (pInfo->rx_first == NULL) {
-                       pInfo->rx_last = NULL;
-               }
-               pInfo->blocks_in_rx_queue--;
-       } else {
-               /* Find block to remove: */
-               for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) {
-                       if (pFind->next == pHeader) {
-                               /* Got it. */
-                               pFind->next = pHeader->next;
-                               pInfo->blocks_in_rx_queue--;
-                               if (pFind->next == NULL) {
-                                       /* Oh, removed the last one! */
-                                       pInfo->rx_last = pFind;
-                               }
-                               break;
-                       }
-               }
-       }
-
-       spin_unlock_irqrestore(&pInfo->lock, flags);
-
-       kfree(pHeader);
-       TRACE_M("remove_from_rx_queue - kfree %p", pHeader);
-
-       TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
-               pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
-}
-
-static void put_char(struct r3964_info *pInfo, unsigned char ch)
-{
-       struct tty_struct *tty = pInfo->tty;
-       /* FIXME: put_char should not be called from an IRQ */
-       tty_put_char(tty, ch);
-       pInfo->bcc ^= ch;
-}
-
-static void flush(struct r3964_info *pInfo)
-{
-       struct tty_struct *tty = pInfo->tty;
-
-       if (tty == NULL || tty->ops->flush_chars == NULL)
-               return;
-       tty->ops->flush_chars(tty);
-}
-
-static void trigger_transmit(struct r3964_info *pInfo)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&pInfo->lock, flags);
-
-       if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) {
-               pInfo->state = R3964_TX_REQUEST;
-               pInfo->nRetry = 0;
-               pInfo->flags &= ~R3964_ERROR;
-               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
-
-               spin_unlock_irqrestore(&pInfo->lock, flags);
-
-               TRACE_PS("trigger_transmit - sent STX");
-
-               put_char(pInfo, STX);
-               flush(pInfo);
-
-               pInfo->bcc = 0;
-       } else {
-               spin_unlock_irqrestore(&pInfo->lock, flags);
-       }
-}
-
-static void retry_transmit(struct r3964_info *pInfo)
-{
-       if (pInfo->nRetry < R3964_MAX_RETRIES) {
-               TRACE_PE("transmission failed. Retry #%d", pInfo->nRetry);
-               pInfo->bcc = 0;
-               put_char(pInfo, STX);
-               flush(pInfo);
-               pInfo->state = R3964_TX_REQUEST;
-               pInfo->nRetry++;
-               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
-       } else {
-               TRACE_PE("transmission failed after %d retries",
-                        R3964_MAX_RETRIES);
-
-               remove_from_tx_queue(pInfo, R3964_TX_FAIL);
-
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               pInfo->state = R3964_IDLE;
-
-               trigger_transmit(pInfo);
-       }
-}
-
-static void transmit_block(struct r3964_info *pInfo)
-{
-       struct tty_struct *tty = pInfo->tty;
-       struct r3964_block_header *pBlock = pInfo->tx_first;
-       int room = 0;
-
-       if (tty == NULL || pBlock == NULL) {
-               return;
-       }
-
-       room = tty_write_room(tty);
-
-       TRACE_PS("transmit_block %p, room %d, length %d",
-                pBlock, room, pBlock->length);
-
-       while (pInfo->tx_position < pBlock->length) {
-               if (room < 2)
-                       break;
-
-               if (pBlock->data[pInfo->tx_position] == DLE) {
-                       /* send additional DLE char: */
-                       put_char(pInfo, DLE);
-               }
-               put_char(pInfo, pBlock->data[pInfo->tx_position++]);
-
-               room--;
-       }
-
-       if ((pInfo->tx_position == pBlock->length) && (room >= 3)) {
-               put_char(pInfo, DLE);
-               put_char(pInfo, ETX);
-               if (pInfo->flags & R3964_BCC) {
-                       put_char(pInfo, pInfo->bcc);
-               }
-               pInfo->state = R3964_WAIT_FOR_TX_ACK;
-               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
-       }
-       flush(pInfo);
-}
-
-static void on_receive_block(struct r3964_info *pInfo)
-{
-       unsigned int length;
-       struct r3964_client_info *pClient;
-       struct r3964_block_header *pBlock;
-
-       length = pInfo->rx_position;
-
-       /* compare byte checksum characters: */
-       if (pInfo->flags & R3964_BCC) {
-               if (pInfo->bcc != pInfo->last_rx) {
-                       TRACE_PE("checksum error - got %x but expected %x",
-                                pInfo->last_rx, pInfo->bcc);
-                       pInfo->flags |= R3964_CHECKSUM;
-               }
-       }
-
-       /* check for errors (parity, overrun,...): */
-       if (pInfo->flags & R3964_ERROR) {
-               TRACE_PE("on_receive_block - transmission failed error %x",
-                        pInfo->flags & R3964_ERROR);
-
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               if (pInfo->nRetry < R3964_MAX_RETRIES) {
-                       pInfo->state = R3964_WAIT_FOR_RX_REPEAT;
-                       pInfo->nRetry++;
-                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC);
-               } else {
-                       TRACE_PE("on_receive_block - failed after max retries");
-                       pInfo->state = R3964_IDLE;
-               }
-               return;
-       }
-
-       /* received block; submit DLE: */
-       put_char(pInfo, DLE);
-       flush(pInfo);
-       del_timer_sync(&pInfo->tmr);
-       TRACE_PS(" rx success: got %d chars", length);
-
-       /* prepare struct r3964_block_header: */
-       pBlock = kmalloc(length + sizeof(struct r3964_block_header),
-                       GFP_KERNEL);
-       TRACE_M("on_receive_block - kmalloc %p", pBlock);
-
-       if (pBlock == NULL)
-               return;
-
-       pBlock->length = length;
-       pBlock->data = ((unsigned char *)pBlock) +
-                       sizeof(struct r3964_block_header);
-       pBlock->locks = 0;
-       pBlock->next = NULL;
-       pBlock->owner = NULL;
-
-       memcpy(pBlock->data, pInfo->rx_buf, length);
-
-       /* queue block into rx_queue: */
-       add_rx_queue(pInfo, pBlock);
-
-       /* notify attached client processes: */
-       for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
-               if (pClient->sig_flags & R3964_SIG_DATA) {
-                       add_msg(pClient, R3964_MSG_DATA, length, R3964_OK,
-                               pBlock);
-               }
-       }
-       wake_up_interruptible(&pInfo->read_wait);
-
-       pInfo->state = R3964_IDLE;
-
-       trigger_transmit(pInfo);
-}
-
-static void receive_char(struct r3964_info *pInfo, const unsigned char c)
-{
-       switch (pInfo->state) {
-       case R3964_TX_REQUEST:
-               if (c == DLE) {
-                       TRACE_PS("TX_REQUEST - got DLE");
-
-                       pInfo->state = R3964_TRANSMITTING;
-                       pInfo->tx_position = 0;
-
-                       transmit_block(pInfo);
-               } else if (c == STX) {
-                       if (pInfo->nRetry == 0) {
-                               TRACE_PE("TX_REQUEST - init conflict");
-                               if (pInfo->priority == R3964_SLAVE) {
-                                       goto start_receiving;
-                               }
-                       } else {
-                               TRACE_PE("TX_REQUEST - secondary init "
-                                       "conflict!? Switching to SLAVE mode "
-                                       "for next rx.");
-                               goto start_receiving;
-                       }
-               } else {
-                       TRACE_PE("TX_REQUEST - char != DLE: %x", c);
-                       retry_transmit(pInfo);
-               }
-               break;
-       case R3964_TRANSMITTING:
-               if (c == NAK) {
-                       TRACE_PE("TRANSMITTING - got NAK");
-                       retry_transmit(pInfo);
-               } else {
-                       TRACE_PE("TRANSMITTING - got invalid char");
-
-                       pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY;
-                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
-               }
-               break;
-       case R3964_WAIT_FOR_TX_ACK:
-               if (c == DLE) {
-                       TRACE_PS("WAIT_FOR_TX_ACK - got DLE");
-                       remove_from_tx_queue(pInfo, R3964_OK);
-
-                       pInfo->state = R3964_IDLE;
-                       trigger_transmit(pInfo);
-               } else {
-                       retry_transmit(pInfo);
-               }
-               break;
-       case R3964_WAIT_FOR_RX_REPEAT:
-               /* FALLTHROUGH */
-       case R3964_IDLE:
-               if (c == STX) {
-                       /* Prevent rx_queue from overflow: */
-                       if (pInfo->blocks_in_rx_queue >=
-                           R3964_MAX_BLOCKS_IN_RX_QUEUE) {
-                               TRACE_PE("IDLE - got STX but no space in "
-                                               "rx_queue!");
-                               pInfo->state = R3964_WAIT_FOR_RX_BUF;
-                               mod_timer(&pInfo->tmr,
-                                         jiffies + R3964_TO_NO_BUF);
-                               break;
-                       }
-start_receiving:
-                       /* Ok, start receiving: */
-                       TRACE_PS("IDLE - got STX");
-                       pInfo->rx_position = 0;
-                       pInfo->last_rx = 0;
-                       pInfo->flags &= ~R3964_ERROR;
-                       pInfo->state = R3964_RECEIVING;
-                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
-                       pInfo->nRetry = 0;
-                       put_char(pInfo, DLE);
-                       flush(pInfo);
-                       pInfo->bcc = 0;
-               }
-               break;
-       case R3964_RECEIVING:
-               if (pInfo->rx_position < RX_BUF_SIZE) {
-                       pInfo->bcc ^= c;
-
-                       if (c == DLE) {
-                               if (pInfo->last_rx == DLE) {
-                                       pInfo->last_rx = 0;
-                                       goto char_to_buf;
-                               }
-                               pInfo->last_rx = DLE;
-                               break;
-                       } else if ((c == ETX) && (pInfo->last_rx == DLE)) {
-                               if (pInfo->flags & R3964_BCC) {
-                                       pInfo->state = R3964_WAIT_FOR_BCC;
-                                       mod_timer(&pInfo->tmr,
-                                                 jiffies + R3964_TO_ZVZ);
-                               } else {
-                                       on_receive_block(pInfo);
-                               }
-                       } else {
-                               pInfo->last_rx = c;
-char_to_buf:
-                               pInfo->rx_buf[pInfo->rx_position++] = c;
-                               mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
-                       }
-               }
-               /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */
-               break;
-       case R3964_WAIT_FOR_BCC:
-               pInfo->last_rx = c;
-               on_receive_block(pInfo);
-               break;
-       }
-}
-
-static void receive_error(struct r3964_info *pInfo, const char flag)
-{
-       switch (flag) {
-       case TTY_NORMAL:
-               break;
-       case TTY_BREAK:
-               TRACE_PE("received break");
-               pInfo->flags |= R3964_BREAK;
-               break;
-       case TTY_PARITY:
-               TRACE_PE("parity error");
-               pInfo->flags |= R3964_PARITY;
-               break;
-       case TTY_FRAME:
-               TRACE_PE("frame error");
-               pInfo->flags |= R3964_FRAME;
-               break;
-       case TTY_OVERRUN:
-               TRACE_PE("frame overrun");
-               pInfo->flags |= R3964_OVERRUN;
-               break;
-       default:
-               TRACE_PE("receive_error - unknown flag %d", flag);
-               pInfo->flags |= R3964_UNKNOWN;
-               break;
-       }
-}
-
-static void on_timeout(unsigned long priv)
-{
-       struct r3964_info *pInfo = (void *)priv;
-
-       switch (pInfo->state) {
-       case R3964_TX_REQUEST:
-               TRACE_PE("TX_REQUEST - timeout");
-               retry_transmit(pInfo);
-               break;
-       case R3964_WAIT_ZVZ_BEFORE_TX_RETRY:
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               retry_transmit(pInfo);
-               break;
-       case R3964_WAIT_FOR_TX_ACK:
-               TRACE_PE("WAIT_FOR_TX_ACK - timeout");
-               retry_transmit(pInfo);
-               break;
-       case R3964_WAIT_FOR_RX_BUF:
-               TRACE_PE("WAIT_FOR_RX_BUF - timeout");
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               pInfo->state = R3964_IDLE;
-               break;
-       case R3964_RECEIVING:
-               TRACE_PE("RECEIVING - timeout after %d chars",
-                        pInfo->rx_position);
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               pInfo->state = R3964_IDLE;
-               break;
-       case R3964_WAIT_FOR_RX_REPEAT:
-               TRACE_PE("WAIT_FOR_RX_REPEAT - timeout");
-               pInfo->state = R3964_IDLE;
-               break;
-       case R3964_WAIT_FOR_BCC:
-               TRACE_PE("WAIT_FOR_BCC - timeout");
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               pInfo->state = R3964_IDLE;
-               break;
-       }
-}
-
-static struct r3964_client_info *findClient(struct r3964_info *pInfo,
-               struct pid *pid)
-{
-       struct r3964_client_info *pClient;
-
-       for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
-               if (pClient->pid == pid) {
-                       return pClient;
-               }
-       }
-       return NULL;
-}
-
-static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg)
-{
-       struct r3964_client_info *pClient;
-       struct r3964_client_info **ppClient;
-       struct r3964_message *pMsg;
-
-       if ((arg & R3964_SIG_ALL) == 0) {
-               /* Remove client from client list */
-               for (ppClient = &pInfo->firstClient; *ppClient;
-                    ppClient = &(*ppClient)->next) {
-                       pClient = *ppClient;
-
-                       if (pClient->pid == pid) {
-                               TRACE_PS("removing client %d from client list",
-                                        pid_nr(pid));
-                               *ppClient = pClient->next;
-                               while (pClient->msg_count) {
-                                       pMsg = remove_msg(pInfo, pClient);
-                                       if (pMsg) {
-                                               kfree(pMsg);
-                                               TRACE_M("enable_signals - msg "
-                                                       "kfree %p", pMsg);
-                                       }
-                               }
-                               put_pid(pClient->pid);
-                               kfree(pClient);
-                               TRACE_M("enable_signals - kfree %p", pClient);
-                               return 0;
-                       }
-               }
-               return -EINVAL;
-       } else {
-               pClient = findClient(pInfo, pid);
-               if (pClient) {
-                       /* update signal options */
-                       pClient->sig_flags = arg;
-               } else {
-                       /* add client to client list */
-                       pClient = kmalloc(sizeof(struct r3964_client_info),
-                                       GFP_KERNEL);
-                       TRACE_M("enable_signals - kmalloc %p", pClient);
-                       if (pClient == NULL)
-                               return -ENOMEM;
-
-                       TRACE_PS("add client %d to client list", pid_nr(pid));
-                       spin_lock_init(&pClient->lock);
-                       pClient->sig_flags = arg;
-                       pClient->pid = get_pid(pid);
-                       pClient->next = pInfo->firstClient;
-                       pClient->first_msg = NULL;
-                       pClient->last_msg = NULL;
-                       pClient->next_block_to_read = NULL;
-                       pClient->msg_count = 0;
-                       pInfo->firstClient = pClient;
-               }
-       }
-
-       return 0;
-}
-
-static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
-                        unsigned char __user * buf)
-{
-       struct r3964_client_info *pClient;
-       struct r3964_block_header *block;
-
-       if (!buf) {
-               return -EINVAL;
-       }
-
-       pClient = findClient(pInfo, pid);
-       if (pClient == NULL) {
-               return -EINVAL;
-       }
-
-       block = pClient->next_block_to_read;
-       if (!block) {
-               return 0;
-       } else {
-               if (copy_to_user(buf, block->data, block->length))
-                       return -EFAULT;
-
-               remove_client_block(pInfo, pClient);
-               return block->length;
-       }
-
-       return -EINVAL;
-}
-
-static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
-               int error_code, struct r3964_block_header *pBlock)
-{
-       struct r3964_message *pMsg;
-       unsigned long flags;
-
-       if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) {
-queue_the_message:
-
-               pMsg = kmalloc(sizeof(struct r3964_message),
-                               error_code ? GFP_ATOMIC : GFP_KERNEL);
-               TRACE_M("add_msg - kmalloc %p", pMsg);
-               if (pMsg == NULL) {
-                       return;
-               }
-
-               spin_lock_irqsave(&pClient->lock, flags);
-
-               pMsg->msg_id = msg_id;
-               pMsg->arg = arg;
-               pMsg->error_code = error_code;
-               pMsg->block = pBlock;
-               pMsg->next = NULL;
-
-               if (pClient->last_msg == NULL) {
-                       pClient->first_msg = pClient->last_msg = pMsg;
-               } else {
-                       pClient->last_msg->next = pMsg;
-                       pClient->last_msg = pMsg;
-               }
-
-               pClient->msg_count++;
-
-               if (pBlock != NULL) {
-                       pBlock->locks++;
-               }
-               spin_unlock_irqrestore(&pClient->lock, flags);
-       } else {
-               if ((pClient->last_msg->msg_id == R3964_MSG_ACK)
-                   && (pClient->last_msg->error_code == R3964_OVERFLOW)) {
-                       pClient->last_msg->arg++;
-                       TRACE_PE("add_msg - inc prev OVERFLOW-msg");
-               } else {
-                       msg_id = R3964_MSG_ACK;
-                       arg = 0;
-                       error_code = R3964_OVERFLOW;
-                       pBlock = NULL;
-                       TRACE_PE("add_msg - queue OVERFLOW-msg");
-                       goto queue_the_message;
-               }
-       }
-       /* Send SIGIO signal to client process: */
-       if (pClient->sig_flags & R3964_USE_SIGIO) {
-               kill_pid(pClient->pid, SIGIO, 1);
-       }
-}
-
-static struct r3964_message *remove_msg(struct r3964_info *pInfo,
-                                       struct r3964_client_info *pClient)
-{
-       struct r3964_message *pMsg = NULL;
-       unsigned long flags;
-
-       if (pClient->first_msg) {
-               spin_lock_irqsave(&pClient->lock, flags);
-
-               pMsg = pClient->first_msg;
-               pClient->first_msg = pMsg->next;
-               if (pClient->first_msg == NULL) {
-                       pClient->last_msg = NULL;
-               }
-
-               pClient->msg_count--;
-               if (pMsg->block) {
-                       remove_client_block(pInfo, pClient);
-                       pClient->next_block_to_read = pMsg->block;
-               }
-               spin_unlock_irqrestore(&pClient->lock, flags);
-       }
-       return pMsg;
-}
-
-static void remove_client_block(struct r3964_info *pInfo,
-                               struct r3964_client_info *pClient)
-{
-       struct r3964_block_header *block;
-
-       TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid));
-
-       block = pClient->next_block_to_read;
-       if (block) {
-               block->locks--;
-               if (block->locks == 0) {
-                       remove_from_rx_queue(pInfo, block);
-               }
-       }
-       pClient->next_block_to_read = NULL;
-}
-
-/*************************************************************
- * Line discipline routines
- *************************************************************/
-
-static int r3964_open(struct tty_struct *tty)
-{
-       struct r3964_info *pInfo;
-
-       TRACE_L("open");
-       TRACE_L("tty=%p, PID=%d, disc_data=%p",
-               tty, current->pid, tty->disc_data);
-
-       pInfo = kmalloc(sizeof(struct r3964_info), GFP_KERNEL);
-       TRACE_M("r3964_open - info kmalloc %p", pInfo);
-
-       if (!pInfo) {
-               printk(KERN_ERR "r3964: failed to alloc info structure\n");
-               return -ENOMEM;
-       }
-
-       pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
-       TRACE_M("r3964_open - rx_buf kmalloc %p", pInfo->rx_buf);
-
-       if (!pInfo->rx_buf) {
-               printk(KERN_ERR "r3964: failed to alloc receive buffer\n");
-               kfree(pInfo);
-               TRACE_M("r3964_open - info kfree %p", pInfo);
-               return -ENOMEM;
-       }
-
-       pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL);
-       TRACE_M("r3964_open - tx_buf kmalloc %p", pInfo->tx_buf);
-
-       if (!pInfo->tx_buf) {
-               printk(KERN_ERR "r3964: failed to alloc transmit buffer\n");
-               kfree(pInfo->rx_buf);
-               TRACE_M("r3964_open - rx_buf kfree %p", pInfo->rx_buf);
-               kfree(pInfo);
-               TRACE_M("r3964_open - info kfree %p", pInfo);
-               return -ENOMEM;
-       }
-
-       spin_lock_init(&pInfo->lock);
-       pInfo->tty = tty;
-       init_waitqueue_head(&pInfo->read_wait);
-       pInfo->priority = R3964_MASTER;
-       pInfo->rx_first = pInfo->rx_last = NULL;
-       pInfo->tx_first = pInfo->tx_last = NULL;
-       pInfo->rx_position = 0;
-       pInfo->tx_position = 0;
-       pInfo->last_rx = 0;
-       pInfo->blocks_in_rx_queue = 0;
-       pInfo->firstClient = NULL;
-       pInfo->state = R3964_IDLE;
-       pInfo->flags = R3964_DEBUG;
-       pInfo->nRetry = 0;
-
-       tty->disc_data = pInfo;
-       tty->receive_room = 65536;
-
-       setup_timer(&pInfo->tmr, on_timeout, (unsigned long)pInfo);
-
-       return 0;
-}
-
-static void r3964_close(struct tty_struct *tty)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       struct r3964_client_info *pClient, *pNext;
-       struct r3964_message *pMsg;
-       struct r3964_block_header *pHeader, *pNextHeader;
-       unsigned long flags;
-
-       TRACE_L("close");
-
-       /*
-        * Make sure that our task queue isn't activated.  If it
-        * is, take it out of the linked list.
-        */
-       del_timer_sync(&pInfo->tmr);
-
-       /* Remove client-structs and message queues: */
-       pClient = pInfo->firstClient;
-       while (pClient) {
-               pNext = pClient->next;
-               while (pClient->msg_count) {
-                       pMsg = remove_msg(pInfo, pClient);
-                       if (pMsg) {
-                               kfree(pMsg);
-                               TRACE_M("r3964_close - msg kfree %p", pMsg);
-                       }
-               }
-               put_pid(pClient->pid);
-               kfree(pClient);
-               TRACE_M("r3964_close - client kfree %p", pClient);
-               pClient = pNext;
-       }
-       /* Remove jobs from tx_queue: */
-       spin_lock_irqsave(&pInfo->lock, flags);
-       pHeader = pInfo->tx_first;
-       pInfo->tx_first = pInfo->tx_last = NULL;
-       spin_unlock_irqrestore(&pInfo->lock, flags);
-
-       while (pHeader) {
-               pNextHeader = pHeader->next;
-               kfree(pHeader);
-               pHeader = pNextHeader;
-       }
-
-       /* Free buffers: */
-       wake_up_interruptible(&pInfo->read_wait);
-       kfree(pInfo->rx_buf);
-       TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf);
-       kfree(pInfo->tx_buf);
-       TRACE_M("r3964_close - tx_buf kfree %p", pInfo->tx_buf);
-       kfree(pInfo);
-       TRACE_M("r3964_close - info kfree %p", pInfo);
-}
-
-static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
-                         unsigned char __user * buf, size_t nr)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       struct r3964_client_info *pClient;
-       struct r3964_message *pMsg;
-       struct r3964_client_message theMsg;
-       int ret;
-
-       TRACE_L("read()");
-
-       tty_lock();
-
-       pClient = findClient(pInfo, task_pid(current));
-       if (pClient) {
-               pMsg = remove_msg(pInfo, pClient);
-               if (pMsg == NULL) {
-                       /* no messages available. */
-                       if (file->f_flags & O_NONBLOCK) {
-                               ret = -EAGAIN;
-                               goto unlock;
-                       }
-                       /* block until there is a message: */
-                       wait_event_interruptible_tty(pInfo->read_wait,
-                                       (pMsg = remove_msg(pInfo, pClient)));
-               }
-
-               /* If we still haven't got a message, we must have been signalled */
-
-               if (!pMsg) {
-                       ret = -EINTR;
-                       goto unlock;
-               }
-
-               /* deliver msg to client process: */
-               theMsg.msg_id = pMsg->msg_id;
-               theMsg.arg = pMsg->arg;
-               theMsg.error_code = pMsg->error_code;
-               ret = sizeof(struct r3964_client_message);
-
-               kfree(pMsg);
-               TRACE_M("r3964_read - msg kfree %p", pMsg);
-
-               if (copy_to_user(buf, &theMsg, ret)) {
-                       ret = -EFAULT;
-                       goto unlock;
-               }
-
-               TRACE_PS("read - return %d", ret);
-               goto unlock;
-       }
-       ret = -EPERM;
-unlock:
-       tty_unlock();
-       return ret;
-}
-
-static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
-                          const unsigned char *data, size_t count)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       struct r3964_block_header *pHeader;
-       struct r3964_client_info *pClient;
-       unsigned char *new_data;
-
-       TRACE_L("write request, %d characters", count);
-/* 
- * Verify the pointers 
- */
-
-       if (!pInfo)
-               return -EIO;
-
-/*
- * Ensure that the caller does not wish to send too much.
- */
-       if (count > R3964_MTU) {
-               if (pInfo->flags & R3964_DEBUG) {
-                       TRACE_L(KERN_WARNING "r3964_write: truncating user "
-                               "packet from %u to mtu %d", count, R3964_MTU);
-               }
-               count = R3964_MTU;
-       }
-/*
- * Allocate a buffer for the data and copy it from the buffer with header prepended
- */
-       new_data = kmalloc(count + sizeof(struct r3964_block_header),
-                       GFP_KERNEL);
-       TRACE_M("r3964_write - kmalloc %p", new_data);
-       if (new_data == NULL) {
-               if (pInfo->flags & R3964_DEBUG) {
-                       printk(KERN_ERR "r3964_write: no memory\n");
-               }
-               return -ENOSPC;
-       }
-
-       pHeader = (struct r3964_block_header *)new_data;
-       pHeader->data = new_data + sizeof(struct r3964_block_header);
-       pHeader->length = count;
-       pHeader->locks = 0;
-       pHeader->owner = NULL;
-
-       tty_lock();
-
-       pClient = findClient(pInfo, task_pid(current));
-       if (pClient) {
-               pHeader->owner = pClient;
-       }
-
-       memcpy(pHeader->data, data, count);     /* We already verified this */
-
-       if (pInfo->flags & R3964_DEBUG) {
-               dump_block(pHeader->data, count);
-       }
-
-/*
- * Add buffer to transmit-queue:
- */
-       add_tx_queue(pInfo, pHeader);
-       trigger_transmit(pInfo);
-
-       tty_unlock();
-
-       return 0;
-}
-
-static int r3964_ioctl(struct tty_struct *tty, struct file *file,
-               unsigned int cmd, unsigned long arg)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       if (pInfo == NULL)
-               return -EINVAL;
-       switch (cmd) {
-       case R3964_ENABLE_SIGNALS:
-               return enable_signals(pInfo, task_pid(current), arg);
-       case R3964_SETPRIORITY:
-               if (arg < R3964_MASTER || arg > R3964_SLAVE)
-                       return -EINVAL;
-               pInfo->priority = arg & 0xff;
-               return 0;
-       case R3964_USE_BCC:
-               if (arg)
-                       pInfo->flags |= R3964_BCC;
-               else
-                       pInfo->flags &= ~R3964_BCC;
-               return 0;
-       case R3964_READ_TELEGRAM:
-               return read_telegram(pInfo, task_pid(current),
-                               (unsigned char __user *)arg);
-       default:
-               return -ENOIOCTLCMD;
-       }
-}
-
-static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
-       TRACE_L("set_termios");
-}
-
-/* Called without the kernel lock held - fine */
-static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
-                       struct poll_table_struct *wait)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       struct r3964_client_info *pClient;
-       struct r3964_message *pMsg = NULL;
-       unsigned long flags;
-       int result = POLLOUT;
-
-       TRACE_L("POLL");
-
-       pClient = findClient(pInfo, task_pid(current));
-       if (pClient) {
-               poll_wait(file, &pInfo->read_wait, wait);
-               spin_lock_irqsave(&pInfo->lock, flags);
-               pMsg = pClient->first_msg;
-               spin_unlock_irqrestore(&pInfo->lock, flags);
-               if (pMsg)
-                       result |= POLLIN | POLLRDNORM;
-       } else {
-               result = -EINVAL;
-       }
-       return result;
-}
-
-static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-                       char *fp, int count)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       const unsigned char *p;
-       char *f, flags = 0;
-       int i;
-
-       for (i = count, p = cp, f = fp; i; i--, p++) {
-               if (f)
-                       flags = *f++;
-               if (flags == TTY_NORMAL) {
-                       receive_char(pInfo, *p);
-               } else {
-                       receive_error(pInfo, flags);
-               }
-
-       }
-}
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_LDISC(N_R3964);
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
deleted file mode 100644 (file)
index 428f4fe..0000000
+++ /dev/null
@@ -1,2121 +0,0 @@
-/*
- * n_tty.c --- implements the N_TTY line discipline.
- *
- * This code used to be in tty_io.c, but things are getting hairy
- * enough that it made sense to split things off.  (The N_TTY
- * processing has changed so much that it's hardly recognizable,
- * anyway...)
- *
- * Note that the open routine for N_TTY is guaranteed never to return
- * an error.  This is because Linux will fall back to setting a line
- * to N_TTY if it can not switch to any other line discipline.
- *
- * Written by Theodore Ts'o, Copyright 1994.
- *
- * This file also contains code originally written by Linus Torvalds,
- * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994.
- *
- * This file may be redistributed under the terms of the GNU General Public
- * License.
- *
- * Reduced memory usage for older ARM systems  - Russell King.
- *
- * 2000/01/20   Fixed SMP locking on put_tty_queue using bits of
- *             the patch by Andrew J. Kroll <ag784@freenet.buffalo.edu>
- *             who actually finally proved there really was a race.
- *
- * 2002/03/18   Implemented n_tty_wakeup to send SIGIO POLL_OUTs to
- *             waiting writing processes-Sapan Bhatia <sapan@corewars.org>.
- *             Also fixed a bug in BLOCKING mode where n_tty_write returns
- *             EAGAIN
- */
-
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/timer.h>
-#include <linux/ctype.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <linux/audit.h>
-#include <linux/file.h>
-#include <linux/uaccess.h>
-#include <linux/module.h>
-
-#include <asm/system.h>
-
-/* number of characters left in xmit buffer before select has we have room */
-#define WAKEUP_CHARS 256
-
-/*
- * This defines the low- and high-watermarks for throttling and
- * unthrottling the TTY driver.  These watermarks are used for
- * controlling the space in the read buffer.
- */
-#define TTY_THRESHOLD_THROTTLE         128 /* now based on remaining room */
-#define TTY_THRESHOLD_UNTHROTTLE       128
-
-/*
- * Special byte codes used in the echo buffer to represent operations
- * or special handling of characters.  Bytes in the echo buffer that
- * are not part of such special blocks are treated as normal character
- * codes.
- */
-#define ECHO_OP_START 0xff
-#define ECHO_OP_MOVE_BACK_COL 0x80
-#define ECHO_OP_SET_CANON_COL 0x81
-#define ECHO_OP_ERASE_TAB 0x82
-
-static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
-                              unsigned char __user *ptr)
-{
-       tty_audit_add_data(tty, &x, 1);
-       return put_user(x, ptr);
-}
-
-/**
- *     n_tty_set__room -       receive space
- *     @tty: terminal
- *
- *     Called by the driver to find out how much data it is
- *     permitted to feed to the line discipline without any being lost
- *     and thus to manage flow control. Not serialized. Answers for the
- *     "instant".
- */
-
-static void n_tty_set_room(struct tty_struct *tty)
-{
-       /* tty->read_cnt is not read locked ? */
-       int     left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
-
-       /*
-        * If we are doing input canonicalization, and there are no
-        * pending newlines, let characters through without limit, so
-        * that erase characters will be handled.  Other excess
-        * characters will be beeped.
-        */
-       if (left <= 0)
-               left = tty->icanon && !tty->canon_data;
-       tty->receive_room = left;
-}
-
-static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
-{
-       if (tty->read_cnt < N_TTY_BUF_SIZE) {
-               tty->read_buf[tty->read_head] = c;
-               tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
-               tty->read_cnt++;
-       }
-}
-
-/**
- *     put_tty_queue           -       add character to tty
- *     @c: character
- *     @tty: tty device
- *
- *     Add a character to the tty read_buf queue. This is done under the
- *     read_lock to serialize character addition and also to protect us
- *     against parallel reads or flushes
- */
-
-static void put_tty_queue(unsigned char c, struct tty_struct *tty)
-{
-       unsigned long flags;
-       /*
-        *      The problem of stomping on the buffers ends here.
-        *      Why didn't anyone see this one coming? --AJK
-       */
-       spin_lock_irqsave(&tty->read_lock, flags);
-       put_tty_queue_nolock(c, tty);
-       spin_unlock_irqrestore(&tty->read_lock, flags);
-}
-
-/**
- *     check_unthrottle        -       allow new receive data
- *     @tty; tty device
- *
- *     Check whether to call the driver unthrottle functions
- *
- *     Can sleep, may be called under the atomic_read_lock mutex but
- *     this is not guaranteed.
- */
-static void check_unthrottle(struct tty_struct *tty)
-{
-       if (tty->count)
-               tty_unthrottle(tty);
-}
-
-/**
- *     reset_buffer_flags      -       reset buffer state
- *     @tty: terminal to reset
- *
- *     Reset the read buffer counters, clear the flags,
- *     and make sure the driver is unthrottled. Called
- *     from n_tty_open() and n_tty_flush_buffer().
- *
- *     Locking: tty_read_lock for read fields.
- */
-
-static void reset_buffer_flags(struct tty_struct *tty)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&tty->read_lock, flags);
-       tty->read_head = tty->read_tail = tty->read_cnt = 0;
-       spin_unlock_irqrestore(&tty->read_lock, flags);
-
-       mutex_lock(&tty->echo_lock);
-       tty->echo_pos = tty->echo_cnt = tty->echo_overrun = 0;
-       mutex_unlock(&tty->echo_lock);
-
-       tty->canon_head = tty->canon_data = tty->erasing = 0;
-       memset(&tty->read_flags, 0, sizeof tty->read_flags);
-       n_tty_set_room(tty);
-       check_unthrottle(tty);
-}
-
-/**
- *     n_tty_flush_buffer      -       clean input queue
- *     @tty:   terminal device
- *
- *     Flush the input buffer. Called when the line discipline is
- *     being closed, when the tty layer wants the buffer flushed (eg
- *     at hangup) or when the N_TTY line discipline internally has to
- *     clean the pending queue (for example some signals).
- *
- *     Locking: ctrl_lock, read_lock.
- */
-
-static void n_tty_flush_buffer(struct tty_struct *tty)
-{
-       unsigned long flags;
-       /* clear everything and unthrottle the driver */
-       reset_buffer_flags(tty);
-
-       if (!tty->link)
-               return;
-
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       if (tty->link->packet) {
-               tty->ctrl_status |= TIOCPKT_FLUSHREAD;
-               wake_up_interruptible(&tty->link->read_wait);
-       }
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-}
-
-/**
- *     n_tty_chars_in_buffer   -       report available bytes
- *     @tty: tty device
- *
- *     Report the number of characters buffered to be delivered to user
- *     at this instant in time.
- *
- *     Locking: read_lock
- */
-
-static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
-{
-       unsigned long flags;
-       ssize_t n = 0;
-
-       spin_lock_irqsave(&tty->read_lock, flags);
-       if (!tty->icanon) {
-               n = tty->read_cnt;
-       } else if (tty->canon_data) {
-               n = (tty->canon_head > tty->read_tail) ?
-                       tty->canon_head - tty->read_tail :
-                       tty->canon_head + (N_TTY_BUF_SIZE - tty->read_tail);
-       }
-       spin_unlock_irqrestore(&tty->read_lock, flags);
-       return n;
-}
-
-/**
- *     is_utf8_continuation    -       utf8 multibyte check
- *     @c: byte to check
- *
- *     Returns true if the utf8 character 'c' is a multibyte continuation
- *     character. We use this to correctly compute the on screen size
- *     of the character when printing
- */
-
-static inline int is_utf8_continuation(unsigned char c)
-{
-       return (c & 0xc0) == 0x80;
-}
-
-/**
- *     is_continuation         -       multibyte check
- *     @c: byte to check
- *
- *     Returns true if the utf8 character 'c' is a multibyte continuation
- *     character and the terminal is in unicode mode.
- */
-
-static inline int is_continuation(unsigned char c, struct tty_struct *tty)
-{
-       return I_IUTF8(tty) && is_utf8_continuation(c);
-}
-
-/**
- *     do_output_char                  -       output one character
- *     @c: character (or partial unicode symbol)
- *     @tty: terminal device
- *     @space: space available in tty driver write buffer
- *
- *     This is a helper function that handles one output character
- *     (including special characters like TAB, CR, LF, etc.),
- *     doing OPOST processing and putting the results in the
- *     tty driver's write buffer.
- *
- *     Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY
- *     and NLDLY.  They simply aren't relevant in the world today.
- *     If you ever need them, add them here.
- *
- *     Returns the number of bytes of buffer space used or -1 if
- *     no space left.
- *
- *     Locking: should be called under the output_lock to protect
- *              the column state and space left in the buffer
- */
-
-static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
-{
-       int     spaces;
-
-       if (!space)
-               return -1;
-
-       switch (c) {
-       case '\n':
-               if (O_ONLRET(tty))
-                       tty->column = 0;
-               if (O_ONLCR(tty)) {
-                       if (space < 2)
-                               return -1;
-                       tty->canon_column = tty->column = 0;
-                       tty->ops->write(tty, "\r\n", 2);
-                       return 2;
-               }
-               tty->canon_column = tty->column;
-               break;
-       case '\r':
-               if (O_ONOCR(tty) && tty->column == 0)
-                       return 0;
-               if (O_OCRNL(tty)) {
-                       c = '\n';
-                       if (O_ONLRET(tty))
-                               tty->canon_column = tty->column = 0;
-                       break;
-               }
-               tty->canon_column = tty->column = 0;
-               break;
-       case '\t':
-               spaces = 8 - (tty->column & 7);
-               if (O_TABDLY(tty) == XTABS) {
-                       if (space < spaces)
-                               return -1;
-                       tty->column += spaces;
-                       tty->ops->write(tty, "        ", spaces);
-                       return spaces;
-               }
-               tty->column += spaces;
-               break;
-       case '\b':
-               if (tty->column > 0)
-                       tty->column--;
-               break;
-       default:
-               if (!iscntrl(c)) {
-                       if (O_OLCUC(tty))
-                               c = toupper(c);
-                       if (!is_continuation(c, tty))
-                               tty->column++;
-               }
-               break;
-       }
-
-       tty_put_char(tty, c);
-       return 1;
-}
-
-/**
- *     process_output                  -       output post processor
- *     @c: character (or partial unicode symbol)
- *     @tty: terminal device
- *
- *     Output one character with OPOST processing.
- *     Returns -1 when the output device is full and the character
- *     must be retried.
- *
- *     Locking: output_lock to protect column state and space left
- *              (also, this is called from n_tty_write under the
- *               tty layer write lock)
- */
-
-static int process_output(unsigned char c, struct tty_struct *tty)
-{
-       int     space, retval;
-
-       mutex_lock(&tty->output_lock);
-
-       space = tty_write_room(tty);
-       retval = do_output_char(c, tty, space);
-
-       mutex_unlock(&tty->output_lock);
-       if (retval < 0)
-               return -1;
-       else
-               return 0;
-}
-
-/**
- *     process_output_block            -       block post processor
- *     @tty: terminal device
- *     @buf: character buffer
- *     @nr: number of bytes to output
- *
- *     Output a block of characters with OPOST processing.
- *     Returns the number of characters output.
- *
- *     This path is used to speed up block console writes, among other
- *     things when processing blocks of output data. It handles only
- *     the simple cases normally found and helps to generate blocks of
- *     symbols for the console driver and thus improve performance.
- *
- *     Locking: output_lock to protect column state and space left
- *              (also, this is called from n_tty_write under the
- *               tty layer write lock)
- */
-
-static ssize_t process_output_block(struct tty_struct *tty,
-                                   const unsigned char *buf, unsigned int nr)
-{
-       int     space;
-       int     i;
-       const unsigned char *cp;
-
-       mutex_lock(&tty->output_lock);
-
-       space = tty_write_room(tty);
-       if (!space) {
-               mutex_unlock(&tty->output_lock);
-               return 0;
-       }
-       if (nr > space)
-               nr = space;
-
-       for (i = 0, cp = buf; i < nr; i++, cp++) {
-               unsigned char c = *cp;
-
-               switch (c) {
-               case '\n':
-                       if (O_ONLRET(tty))
-                               tty->column = 0;
-                       if (O_ONLCR(tty))
-                               goto break_out;
-                       tty->canon_column = tty->column;
-                       break;
-               case '\r':
-                       if (O_ONOCR(tty) && tty->column == 0)
-                               goto break_out;
-                       if (O_OCRNL(tty))
-                               goto break_out;
-                       tty->canon_column = tty->column = 0;
-                       break;
-               case '\t':
-                       goto break_out;
-               case '\b':
-                       if (tty->column > 0)
-                               tty->column--;
-                       break;
-               default:
-                       if (!iscntrl(c)) {
-                               if (O_OLCUC(tty))
-                                       goto break_out;
-                               if (!is_continuation(c, tty))
-                                       tty->column++;
-                       }
-                       break;
-               }
-       }
-break_out:
-       i = tty->ops->write(tty, buf, i);
-
-       mutex_unlock(&tty->output_lock);
-       return i;
-}
-
-/**
- *     process_echoes  -       write pending echo characters
- *     @tty: terminal device
- *
- *     Write previously buffered echo (and other ldisc-generated)
- *     characters to the tty.
- *
- *     Characters generated by the ldisc (including echoes) need to
- *     be buffered because the driver's write buffer can fill during
- *     heavy program output.  Echoing straight to the driver will
- *     often fail under these conditions, causing lost characters and
- *     resulting mismatches of ldisc state information.
- *
- *     Since the ldisc state must represent the characters actually sent
- *     to the driver at the time of the write, operations like certain
- *     changes in column state are also saved in the buffer and executed
- *     here.
- *
- *     A circular fifo buffer is used so that the most recent characters
- *     are prioritized.  Also, when control characters are echoed with a
- *     prefixed "^", the pair is treated atomically and thus not separated.
- *
- *     Locking: output_lock to protect column state and space left,
- *              echo_lock to protect the echo buffer
- */
-
-static void process_echoes(struct tty_struct *tty)
-{
-       int     space, nr;
-       unsigned char c;
-       unsigned char *cp, *buf_end;
-
-       if (!tty->echo_cnt)
-               return;
-
-       mutex_lock(&tty->output_lock);
-       mutex_lock(&tty->echo_lock);
-
-       space = tty_write_room(tty);
-
-       buf_end = tty->echo_buf + N_TTY_BUF_SIZE;
-       cp = tty->echo_buf + tty->echo_pos;
-       nr = tty->echo_cnt;
-       while (nr > 0) {
-               c = *cp;
-               if (c == ECHO_OP_START) {
-                       unsigned char op;
-                       unsigned char *opp;
-                       int no_space_left = 0;
-
-                       /*
-                        * If the buffer byte is the start of a multi-byte
-                        * operation, get the next byte, which is either the
-                        * op code or a control character value.
-                        */
-                       opp = cp + 1;
-                       if (opp == buf_end)
-                               opp -= N_TTY_BUF_SIZE;
-                       op = *opp;
-
-                       switch (op) {
-                               unsigned int num_chars, num_bs;
-
-                       case ECHO_OP_ERASE_TAB:
-                               if (++opp == buf_end)
-                                       opp -= N_TTY_BUF_SIZE;
-                               num_chars = *opp;
-
-                               /*
-                                * Determine how many columns to go back
-                                * in order to erase the tab.
-                                * This depends on the number of columns
-                                * used by other characters within the tab
-                                * area.  If this (modulo 8) count is from
-                                * the start of input rather than from a
-                                * previous tab, we offset by canon column.
-                                * Otherwise, tab spacing is normal.
-                                */
-                               if (!(num_chars & 0x80))
-                                       num_chars += tty->canon_column;
-                               num_bs = 8 - (num_chars & 7);
-
-                               if (num_bs > space) {
-                                       no_space_left = 1;
-                                       break;
-                               }
-                               space -= num_bs;
-                               while (num_bs--) {
-                                       tty_put_char(tty, '\b');
-                                       if (tty->column > 0)
-                                               tty->column--;
-                               }
-                               cp += 3;
-                               nr -= 3;
-                               break;
-
-                       case ECHO_OP_SET_CANON_COL:
-                               tty->canon_column = tty->column;
-                               cp += 2;
-                               nr -= 2;
-                               break;
-
-                       case ECHO_OP_MOVE_BACK_COL:
-                               if (tty->column > 0)
-                                       tty->column--;
-                               cp += 2;
-                               nr -= 2;
-                               break;
-
-                       case ECHO_OP_START:
-                               /* This is an escaped echo op start code */
-                               if (!space) {
-                                       no_space_left = 1;
-                                       break;
-                               }
-                               tty_put_char(tty, ECHO_OP_START);
-                               tty->column++;
-                               space--;
-                               cp += 2;
-                               nr -= 2;
-                               break;
-
-                       default:
-                               /*
-                                * If the op is not a special byte code,
-                                * it is a ctrl char tagged to be echoed
-                                * as "^X" (where X is the letter
-                                * representing the control char).
-                                * Note that we must ensure there is
-                                * enough space for the whole ctrl pair.
-                                *
-                                */
-                               if (space < 2) {
-                                       no_space_left = 1;
-                                       break;
-                               }
-                               tty_put_char(tty, '^');
-                               tty_put_char(tty, op ^ 0100);
-                               tty->column += 2;
-                               space -= 2;
-                               cp += 2;
-                               nr -= 2;
-                       }
-
-                       if (no_space_left)
-                               break;
-               } else {
-                       if (O_OPOST(tty) &&
-                           !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
-                               int retval = do_output_char(c, tty, space);
-                               if (retval < 0)
-                                       break;
-                               space -= retval;
-                       } else {
-                               if (!space)
-                                       break;
-                               tty_put_char(tty, c);
-                               space -= 1;
-                       }
-                       cp += 1;
-                       nr -= 1;
-               }
-
-               /* When end of circular buffer reached, wrap around */
-               if (cp >= buf_end)
-                       cp -= N_TTY_BUF_SIZE;
-       }
-
-       if (nr == 0) {
-               tty->echo_pos = 0;
-               tty->echo_cnt = 0;
-               tty->echo_overrun = 0;
-       } else {
-               int num_processed = tty->echo_cnt - nr;
-               tty->echo_pos += num_processed;
-               tty->echo_pos &= N_TTY_BUF_SIZE - 1;
-               tty->echo_cnt = nr;
-               if (num_processed > 0)
-                       tty->echo_overrun = 0;
-       }
-
-       mutex_unlock(&tty->echo_lock);
-       mutex_unlock(&tty->output_lock);
-
-       if (tty->ops->flush_chars)
-               tty->ops->flush_chars(tty);
-}
-
-/**
- *     add_echo_byte   -       add a byte to the echo buffer
- *     @c: unicode byte to echo
- *     @tty: terminal device
- *
- *     Add a character or operation byte to the echo buffer.
- *
- *     Should be called under the echo lock to protect the echo buffer.
- */
-
-static void add_echo_byte(unsigned char c, struct tty_struct *tty)
-{
-       int     new_byte_pos;
-
-       if (tty->echo_cnt == N_TTY_BUF_SIZE) {
-               /* Circular buffer is already at capacity */
-               new_byte_pos = tty->echo_pos;
-
-               /*
-                * Since the buffer start position needs to be advanced,
-                * be sure to step by a whole operation byte group.
-                */
-               if (tty->echo_buf[tty->echo_pos] == ECHO_OP_START) {
-                       if (tty->echo_buf[(tty->echo_pos + 1) &
-                                         (N_TTY_BUF_SIZE - 1)] ==
-                                               ECHO_OP_ERASE_TAB) {
-                               tty->echo_pos += 3;
-                               tty->echo_cnt -= 2;
-                       } else {
-                               tty->echo_pos += 2;
-                               tty->echo_cnt -= 1;
-                       }
-               } else {
-                       tty->echo_pos++;
-               }
-               tty->echo_pos &= N_TTY_BUF_SIZE - 1;
-
-               tty->echo_overrun = 1;
-       } else {
-               new_byte_pos = tty->echo_pos + tty->echo_cnt;
-               new_byte_pos &= N_TTY_BUF_SIZE - 1;
-               tty->echo_cnt++;
-       }
-
-       tty->echo_buf[new_byte_pos] = c;
-}
-
-/**
- *     echo_move_back_col      -       add operation to move back a column
- *     @tty: terminal device
- *
- *     Add an operation to the echo buffer to move back one column.
- *
- *     Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_move_back_col(struct tty_struct *tty)
-{
-       mutex_lock(&tty->echo_lock);
-
-       add_echo_byte(ECHO_OP_START, tty);
-       add_echo_byte(ECHO_OP_MOVE_BACK_COL, tty);
-
-       mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *     echo_set_canon_col      -       add operation to set the canon column
- *     @tty: terminal device
- *
- *     Add an operation to the echo buffer to set the canon column
- *     to the current column.
- *
- *     Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_set_canon_col(struct tty_struct *tty)
-{
-       mutex_lock(&tty->echo_lock);
-
-       add_echo_byte(ECHO_OP_START, tty);
-       add_echo_byte(ECHO_OP_SET_CANON_COL, tty);
-
-       mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *     echo_erase_tab  -       add operation to erase a tab
- *     @num_chars: number of character columns already used
- *     @after_tab: true if num_chars starts after a previous tab
- *     @tty: terminal device
- *
- *     Add an operation to the echo buffer to erase a tab.
- *
- *     Called by the eraser function, which knows how many character
- *     columns have been used since either a previous tab or the start
- *     of input.  This information will be used later, along with
- *     canon column (if applicable), to go back the correct number
- *     of columns.
- *
- *     Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_erase_tab(unsigned int num_chars, int after_tab,
-                          struct tty_struct *tty)
-{
-       mutex_lock(&tty->echo_lock);
-
-       add_echo_byte(ECHO_OP_START, tty);
-       add_echo_byte(ECHO_OP_ERASE_TAB, tty);
-
-       /* We only need to know this modulo 8 (tab spacing) */
-       num_chars &= 7;
-
-       /* Set the high bit as a flag if num_chars is after a previous tab */
-       if (after_tab)
-               num_chars |= 0x80;
-
-       add_echo_byte(num_chars, tty);
-
-       mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *     echo_char_raw   -       echo a character raw
- *     @c: unicode byte to echo
- *     @tty: terminal device
- *
- *     Echo user input back onto the screen. This must be called only when
- *     L_ECHO(tty) is true. Called from the driver receive_buf path.
- *
- *     This variant does not treat control characters specially.
- *
- *     Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_char_raw(unsigned char c, struct tty_struct *tty)
-{
-       mutex_lock(&tty->echo_lock);
-
-       if (c == ECHO_OP_START) {
-               add_echo_byte(ECHO_OP_START, tty);
-               add_echo_byte(ECHO_OP_START, tty);
-       } else {
-               add_echo_byte(c, tty);
-       }
-
-       mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *     echo_char       -       echo a character
- *     @c: unicode byte to echo
- *     @tty: terminal device
- *
- *     Echo user input back onto the screen. This must be called only when
- *     L_ECHO(tty) is true. Called from the driver receive_buf path.
- *
- *     This variant tags control characters to be echoed as "^X"
- *     (where X is the letter representing the control char).
- *
- *     Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_char(unsigned char c, struct tty_struct *tty)
-{
-       mutex_lock(&tty->echo_lock);
-
-       if (c == ECHO_OP_START) {
-               add_echo_byte(ECHO_OP_START, tty);
-               add_echo_byte(ECHO_OP_START, tty);
-       } else {
-               if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t')
-                       add_echo_byte(ECHO_OP_START, tty);
-               add_echo_byte(c, tty);
-       }
-
-       mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *     finish_erasing          -       complete erase
- *     @tty: tty doing the erase
- */
-
-static inline void finish_erasing(struct tty_struct *tty)
-{
-       if (tty->erasing) {
-               echo_char_raw('/', tty);
-               tty->erasing = 0;
-       }
-}
-
-/**
- *     eraser          -       handle erase function
- *     @c: character input
- *     @tty: terminal device
- *
- *     Perform erase and necessary output when an erase character is
- *     present in the stream from the driver layer. Handles the complexities
- *     of UTF-8 multibyte symbols.
- *
- *     Locking: read_lock for tty buffers
- */
-
-static void eraser(unsigned char c, struct tty_struct *tty)
-{
-       enum { ERASE, WERASE, KILL } kill_type;
-       int head, seen_alnums, cnt;
-       unsigned long flags;
-
-       /* FIXME: locking needed ? */
-       if (tty->read_head == tty->canon_head) {
-               /* process_output('\a', tty); */ /* what do you think? */
-               return;
-       }
-       if (c == ERASE_CHAR(tty))
-               kill_type = ERASE;
-       else if (c == WERASE_CHAR(tty))
-               kill_type = WERASE;
-       else {
-               if (!L_ECHO(tty)) {
-                       spin_lock_irqsave(&tty->read_lock, flags);
-                       tty->read_cnt -= ((tty->read_head - tty->canon_head) &
-                                         (N_TTY_BUF_SIZE - 1));
-                       tty->read_head = tty->canon_head;
-                       spin_unlock_irqrestore(&tty->read_lock, flags);
-                       return;
-               }
-               if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
-                       spin_lock_irqsave(&tty->read_lock, flags);
-                       tty->read_cnt -= ((tty->read_head - tty->canon_head) &
-                                         (N_TTY_BUF_SIZE - 1));
-                       tty->read_head = tty->canon_head;
-                       spin_unlock_irqrestore(&tty->read_lock, flags);
-                       finish_erasing(tty);
-                       echo_char(KILL_CHAR(tty), tty);
-                       /* Add a newline if ECHOK is on and ECHOKE is off. */
-                       if (L_ECHOK(tty))
-                               echo_char_raw('\n', tty);
-                       return;
-               }
-               kill_type = KILL;
-       }
-
-       seen_alnums = 0;
-       /* FIXME: Locking ?? */
-       while (tty->read_head != tty->canon_head) {
-               head = tty->read_head;
-
-               /* erase a single possibly multibyte character */
-               do {
-                       head = (head - 1) & (N_TTY_BUF_SIZE-1);
-                       c = tty->read_buf[head];
-               } while (is_continuation(c, tty) && head != tty->canon_head);
-
-               /* do not partially erase */
-               if (is_continuation(c, tty))
-                       break;
-
-               if (kill_type == WERASE) {
-                       /* Equivalent to BSD's ALTWERASE. */
-                       if (isalnum(c) || c == '_')
-                               seen_alnums++;
-                       else if (seen_alnums)
-                               break;
-               }
-               cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1);
-               spin_lock_irqsave(&tty->read_lock, flags);
-               tty->read_head = head;
-               tty->read_cnt -= cnt;
-               spin_unlock_irqrestore(&tty->read_lock, flags);
-               if (L_ECHO(tty)) {
-                       if (L_ECHOPRT(tty)) {
-                               if (!tty->erasing) {
-                                       echo_char_raw('\\', tty);
-                                       tty->erasing = 1;
-                               }
-                               /* if cnt > 1, output a multi-byte character */
-                               echo_char(c, tty);
-                               while (--cnt > 0) {
-                                       head = (head+1) & (N_TTY_BUF_SIZE-1);
-                                       echo_char_raw(tty->read_buf[head], tty);
-                                       echo_move_back_col(tty);
-                               }
-                       } else if (kill_type == ERASE && !L_ECHOE(tty)) {
-                               echo_char(ERASE_CHAR(tty), tty);
-                       } else if (c == '\t') {
-                               unsigned int num_chars = 0;
-                               int after_tab = 0;
-                               unsigned long tail = tty->read_head;
-
-                               /*
-                                * Count the columns used for characters
-                                * since the start of input or after a
-                                * previous tab.
-                                * This info is used to go back the correct
-                                * number of columns.
-                                */
-                               while (tail != tty->canon_head) {
-                                       tail = (tail-1) & (N_TTY_BUF_SIZE-1);
-                                       c = tty->read_buf[tail];
-                                       if (c == '\t') {
-                                               after_tab = 1;
-                                               break;
-                                       } else if (iscntrl(c)) {
-                                               if (L_ECHOCTL(tty))
-                                                       num_chars += 2;
-                                       } else if (!is_continuation(c, tty)) {
-                                               num_chars++;
-                                       }
-                               }
-                               echo_erase_tab(num_chars, after_tab, tty);
-                       } else {
-                               if (iscntrl(c) && L_ECHOCTL(tty)) {
-                                       echo_char_raw('\b', tty);
-                                       echo_char_raw(' ', tty);
-                                       echo_char_raw('\b', tty);
-                               }
-                               if (!iscntrl(c) || L_ECHOCTL(tty)) {
-                                       echo_char_raw('\b', tty);
-                                       echo_char_raw(' ', tty);
-                                       echo_char_raw('\b', tty);
-                               }
-                       }
-               }
-               if (kill_type == ERASE)
-                       break;
-       }
-       if (tty->read_head == tty->canon_head && L_ECHO(tty))
-               finish_erasing(tty);
-}
-
-/**
- *     isig            -       handle the ISIG optio
- *     @sig: signal
- *     @tty: terminal
- *     @flush: force flush
- *
- *     Called when a signal is being sent due to terminal input. This
- *     may caus terminal flushing to take place according to the termios
- *     settings and character used. Called from the driver receive_buf
- *     path so serialized.
- *
- *     Locking: ctrl_lock, read_lock (both via flush buffer)
- */
-
-static inline void isig(int sig, struct tty_struct *tty, int flush)
-{
-       if (tty->pgrp)
-               kill_pgrp(tty->pgrp, sig, 1);
-       if (flush || !L_NOFLSH(tty)) {
-               n_tty_flush_buffer(tty);
-               tty_driver_flush_buffer(tty);
-       }
-}
-
-/**
- *     n_tty_receive_break     -       handle break
- *     @tty: terminal
- *
- *     An RS232 break event has been hit in the incoming bitstream. This
- *     can cause a variety of events depending upon the termios settings.
- *
- *     Called from the receive_buf path so single threaded.
- */
-
-static inline void n_tty_receive_break(struct tty_struct *tty)
-{
-       if (I_IGNBRK(tty))
-               return;
-       if (I_BRKINT(tty)) {
-               isig(SIGINT, tty, 1);
-               return;
-       }
-       if (I_PARMRK(tty)) {
-               put_tty_queue('\377', tty);
-               put_tty_queue('\0', tty);
-       }
-       put_tty_queue('\0', tty);
-       wake_up_interruptible(&tty->read_wait);
-}
-
-/**
- *     n_tty_receive_overrun   -       handle overrun reporting
- *     @tty: terminal
- *
- *     Data arrived faster than we could process it. While the tty
- *     driver has flagged this the bits that were missed are gone
- *     forever.
- *
- *     Called from the receive_buf path so single threaded. Does not
- *     need locking as num_overrun and overrun_time are function
- *     private.
- */
-
-static inline void n_tty_receive_overrun(struct tty_struct *tty)
-{
-       char buf[64];
-
-       tty->num_overrun++;
-       if (time_before(tty->overrun_time, jiffies - HZ) ||
-                       time_after(tty->overrun_time, jiffies)) {
-               printk(KERN_WARNING "%s: %d input overrun(s)\n",
-                       tty_name(tty, buf),
-                       tty->num_overrun);
-               tty->overrun_time = jiffies;
-               tty->num_overrun = 0;
-       }
-}
-
-/**
- *     n_tty_receive_parity_error      -       error notifier
- *     @tty: terminal device
- *     @c: character
- *
- *     Process a parity error and queue the right data to indicate
- *     the error case if necessary. Locking as per n_tty_receive_buf.
- */
-static inline void n_tty_receive_parity_error(struct tty_struct *tty,
-                                             unsigned char c)
-{
-       if (I_IGNPAR(tty))
-               return;
-       if (I_PARMRK(tty)) {
-               put_tty_queue('\377', tty);
-               put_tty_queue('\0', tty);
-               put_tty_queue(c, tty);
-       } else  if (I_INPCK(tty))
-               put_tty_queue('\0', tty);
-       else
-               put_tty_queue(c, tty);
-       wake_up_interruptible(&tty->read_wait);
-}
-
-/**
- *     n_tty_receive_char      -       perform processing
- *     @tty: terminal device
- *     @c: character
- *
- *     Process an individual character of input received from the driver.
- *     This is serialized with respect to itself by the rules for the
- *     driver above.
- */
-
-static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
-{
-       unsigned long flags;
-       int parmrk;
-
-       if (tty->raw) {
-               put_tty_queue(c, tty);
-               return;
-       }
-
-       if (I_ISTRIP(tty))
-               c &= 0x7f;
-       if (I_IUCLC(tty) && L_IEXTEN(tty))
-               c = tolower(c);
-
-       if (L_EXTPROC(tty)) {
-               put_tty_queue(c, tty);
-               return;
-       }
-
-       if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
-           I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty) &&
-           c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty)) {
-               start_tty(tty);
-               process_echoes(tty);
-       }
-
-       if (tty->closing) {
-               if (I_IXON(tty)) {
-                       if (c == START_CHAR(tty)) {
-                               start_tty(tty);
-                               process_echoes(tty);
-                       } else if (c == STOP_CHAR(tty))
-                               stop_tty(tty);
-               }
-               return;
-       }
-
-       /*
-        * If the previous character was LNEXT, or we know that this
-        * character is not one of the characters that we'll have to
-        * handle specially, do shortcut processing to speed things
-        * up.
-        */
-       if (!test_bit(c, tty->process_char_map) || tty->lnext) {
-               tty->lnext = 0;
-               parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
-               if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
-                       /* beep if no space */
-                       if (L_ECHO(tty))
-                               process_output('\a', tty);
-                       return;
-               }
-               if (L_ECHO(tty)) {
-                       finish_erasing(tty);
-                       /* Record the column of first canon char. */
-                       if (tty->canon_head == tty->read_head)
-                               echo_set_canon_col(tty);
-                       echo_char(c, tty);
-                       process_echoes(tty);
-               }
-               if (parmrk)
-                       put_tty_queue(c, tty);
-               put_tty_queue(c, tty);
-               return;
-       }
-
-       if (I_IXON(tty)) {
-               if (c == START_CHAR(tty)) {
-                       start_tty(tty);
-                       process_echoes(tty);
-                       return;
-               }
-               if (c == STOP_CHAR(tty)) {
-                       stop_tty(tty);
-                       return;
-               }
-       }
-
-       if (L_ISIG(tty)) {
-               int signal;
-               signal = SIGINT;
-               if (c == INTR_CHAR(tty))
-                       goto send_signal;
-               signal = SIGQUIT;
-               if (c == QUIT_CHAR(tty))
-                       goto send_signal;
-               signal = SIGTSTP;
-               if (c == SUSP_CHAR(tty)) {
-send_signal:
-                       /*
-                        * Note that we do not use isig() here because we want
-                        * the order to be:
-                        * 1) flush, 2) echo, 3) signal
-                        */
-                       if (!L_NOFLSH(tty)) {
-                               n_tty_flush_buffer(tty);
-                               tty_driver_flush_buffer(tty);
-                       }
-                       if (I_IXON(tty))
-                               start_tty(tty);
-                       if (L_ECHO(tty)) {
-                               echo_char(c, tty);
-                               process_echoes(tty);
-                       }
-                       if (tty->pgrp)
-                               kill_pgrp(tty->pgrp, signal, 1);
-                       return;
-               }
-       }
-
-       if (c == '\r') {
-               if (I_IGNCR(tty))
-                       return;
-               if (I_ICRNL(tty))
-                       c = '\n';
-       } else if (c == '\n' && I_INLCR(tty))
-               c = '\r';
-
-       if (tty->icanon) {
-               if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
-                   (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
-                       eraser(c, tty);
-                       process_echoes(tty);
-                       return;
-               }
-               if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
-                       tty->lnext = 1;
-                       if (L_ECHO(tty)) {
-                               finish_erasing(tty);
-                               if (L_ECHOCTL(tty)) {
-                                       echo_char_raw('^', tty);
-                                       echo_char_raw('\b', tty);
-                                       process_echoes(tty);
-                               }
-                       }
-                       return;
-               }
-               if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
-                   L_IEXTEN(tty)) {
-                       unsigned long tail = tty->canon_head;
-
-                       finish_erasing(tty);
-                       echo_char(c, tty);
-                       echo_char_raw('\n', tty);
-                       while (tail != tty->read_head) {
-                               echo_char(tty->read_buf[tail], tty);
-                               tail = (tail+1) & (N_TTY_BUF_SIZE-1);
-                       }
-                       process_echoes(tty);
-                       return;
-               }
-               if (c == '\n') {
-                       if (tty->read_cnt >= N_TTY_BUF_SIZE) {
-                               if (L_ECHO(tty))
-                                       process_output('\a', tty);
-                               return;
-                       }
-                       if (L_ECHO(tty) || L_ECHONL(tty)) {
-                               echo_char_raw('\n', tty);
-                               process_echoes(tty);
-                       }
-                       goto handle_newline;
-               }
-               if (c == EOF_CHAR(tty)) {
-                       if (tty->read_cnt >= N_TTY_BUF_SIZE)
-                               return;
-                       if (tty->canon_head != tty->read_head)
-                               set_bit(TTY_PUSH, &tty->flags);
-                       c = __DISABLED_CHAR;
-                       goto handle_newline;
-               }
-               if ((c == EOL_CHAR(tty)) ||
-                   (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
-                       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
-                                ? 1 : 0;
-                       if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
-                               if (L_ECHO(tty))
-                                       process_output('\a', tty);
-                               return;
-                       }
-                       /*
-                        * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
-                        */
-                       if (L_ECHO(tty)) {
-                               /* Record the column of first canon char. */
-                               if (tty->canon_head == tty->read_head)
-                                       echo_set_canon_col(tty);
-                               echo_char(c, tty);
-                               process_echoes(tty);
-                       }
-                       /*
-                        * XXX does PARMRK doubling happen for
-                        * EOL_CHAR and EOL2_CHAR?
-                        */
-                       if (parmrk)
-                               put_tty_queue(c, tty);
-
-handle_newline:
-                       spin_lock_irqsave(&tty->read_lock, flags);
-                       set_bit(tty->read_head, tty->read_flags);
-                       put_tty_queue_nolock(c, tty);
-                       tty->canon_head = tty->read_head;
-                       tty->canon_data++;
-                       spin_unlock_irqrestore(&tty->read_lock, flags);
-                       kill_fasync(&tty->fasync, SIGIO, POLL_IN);
-                       if (waitqueue_active(&tty->read_wait))
-                               wake_up_interruptible(&tty->read_wait);
-                       return;
-               }
-       }
-
-       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
-       if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
-               /* beep if no space */
-               if (L_ECHO(tty))
-                       process_output('\a', tty);
-               return;
-       }
-       if (L_ECHO(tty)) {
-               finish_erasing(tty);
-               if (c == '\n')
-                       echo_char_raw('\n', tty);
-               else {
-                       /* Record the column of first canon char. */
-                       if (tty->canon_head == tty->read_head)
-                               echo_set_canon_col(tty);
-                       echo_char(c, tty);
-               }
-               process_echoes(tty);
-       }
-
-       if (parmrk)
-               put_tty_queue(c, tty);
-
-       put_tty_queue(c, tty);
-}
-
-
-/**
- *     n_tty_write_wakeup      -       asynchronous I/O notifier
- *     @tty: tty device
- *
- *     Required for the ptys, serial driver etc. since processes
- *     that attach themselves to the master and rely on ASYNC
- *     IO must be woken up
- */
-
-static void n_tty_write_wakeup(struct tty_struct *tty)
-{
-       if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
-               kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
-}
-
-/**
- *     n_tty_receive_buf       -       data receive
- *     @tty: terminal device
- *     @cp: buffer
- *     @fp: flag buffer
- *     @count: characters
- *
- *     Called by the terminal driver when a block of characters has
- *     been received. This function must be called from soft contexts
- *     not from interrupt context. The driver is responsible for making
- *     calls one at a time and in order (or using flush_to_ldisc)
- */
-
-static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-                             char *fp, int count)
-{
-       const unsigned char *p;
-       char *f, flags = TTY_NORMAL;
-       int     i;
-       char    buf[64];
-       unsigned long cpuflags;
-
-       if (!tty->read_buf)
-               return;
-
-       if (tty->real_raw) {
-               spin_lock_irqsave(&tty->read_lock, cpuflags);
-               i = min(N_TTY_BUF_SIZE - tty->read_cnt,
-                       N_TTY_BUF_SIZE - tty->read_head);
-               i = min(count, i);
-               memcpy(tty->read_buf + tty->read_head, cp, i);
-               tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
-               tty->read_cnt += i;
-               cp += i;
-               count -= i;
-
-               i = min(N_TTY_BUF_SIZE - tty->read_cnt,
-                       N_TTY_BUF_SIZE - tty->read_head);
-               i = min(count, i);
-               memcpy(tty->read_buf + tty->read_head, cp, i);
-               tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
-               tty->read_cnt += i;
-               spin_unlock_irqrestore(&tty->read_lock, cpuflags);
-       } else {
-               for (i = count, p = cp, f = fp; i; i--, p++) {
-                       if (f)
-                               flags = *f++;
-                       switch (flags) {
-                       case TTY_NORMAL:
-                               n_tty_receive_char(tty, *p);
-                               break;
-                       case TTY_BREAK:
-                               n_tty_receive_break(tty);
-                               break;
-                       case TTY_PARITY:
-                       case TTY_FRAME:
-                               n_tty_receive_parity_error(tty, *p);
-                               break;
-                       case TTY_OVERRUN:
-                               n_tty_receive_overrun(tty);
-                               break;
-                       default:
-                               printk(KERN_ERR "%s: unknown flag %d\n",
-                                      tty_name(tty, buf), flags);
-                               break;
-                       }
-               }
-               if (tty->ops->flush_chars)
-                       tty->ops->flush_chars(tty);
-       }
-
-       n_tty_set_room(tty);
-
-       if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) ||
-               L_EXTPROC(tty)) {
-               kill_fasync(&tty->fasync, SIGIO, POLL_IN);
-               if (waitqueue_active(&tty->read_wait))
-                       wake_up_interruptible(&tty->read_wait);
-       }
-
-       /*
-        * Check the remaining room for the input canonicalization
-        * mode.  We don't want to throttle the driver if we're in
-        * canonical mode and don't have a newline yet!
-        */
-       if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
-               tty_throttle(tty);
-}
-
-int is_ignored(int sig)
-{
-       return (sigismember(&current->blocked, sig) ||
-               current->sighand->action[sig-1].sa.sa_handler == SIG_IGN);
-}
-
-/**
- *     n_tty_set_termios       -       termios data changed
- *     @tty: terminal
- *     @old: previous data
- *
- *     Called by the tty layer when the user changes termios flags so
- *     that the line discipline can plan ahead. This function cannot sleep
- *     and is protected from re-entry by the tty layer. The user is
- *     guaranteed that this function will not be re-entered or in progress
- *     when the ldisc is closed.
- *
- *     Locking: Caller holds tty->termios_mutex
- */
-
-static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
-       int canon_change = 1;
-       BUG_ON(!tty);
-
-       if (old)
-               canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
-       if (canon_change) {
-               memset(&tty->read_flags, 0, sizeof tty->read_flags);
-               tty->canon_head = tty->read_tail;
-               tty->canon_data = 0;
-               tty->erasing = 0;
-       }
-
-       if (canon_change && !L_ICANON(tty) && tty->read_cnt)
-               wake_up_interruptible(&tty->read_wait);
-
-       tty->icanon = (L_ICANON(tty) != 0);
-       if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
-               tty->raw = 1;
-               tty->real_raw = 1;
-               n_tty_set_room(tty);
-               return;
-       }
-       if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
-           I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
-           I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
-           I_PARMRK(tty)) {
-               memset(tty->process_char_map, 0, 256/8);
-
-               if (I_IGNCR(tty) || I_ICRNL(tty))
-                       set_bit('\r', tty->process_char_map);
-               if (I_INLCR(tty))
-                       set_bit('\n', tty->process_char_map);
-
-               if (L_ICANON(tty)) {
-                       set_bit(ERASE_CHAR(tty), tty->process_char_map);
-                       set_bit(KILL_CHAR(tty), tty->process_char_map);
-                       set_bit(EOF_CHAR(tty), tty->process_char_map);
-                       set_bit('\n', tty->process_char_map);
-                       set_bit(EOL_CHAR(tty), tty->process_char_map);
-                       if (L_IEXTEN(tty)) {
-                               set_bit(WERASE_CHAR(tty),
-                                       tty->process_char_map);
-                               set_bit(LNEXT_CHAR(tty),
-                                       tty->process_char_map);
-                               set_bit(EOL2_CHAR(tty),
-                                       tty->process_char_map);
-                               if (L_ECHO(tty))
-                                       set_bit(REPRINT_CHAR(tty),
-                                               tty->process_char_map);
-                       }
-               }
-               if (I_IXON(tty)) {
-                       set_bit(START_CHAR(tty), tty->process_char_map);
-                       set_bit(STOP_CHAR(tty), tty->process_char_map);
-               }
-               if (L_ISIG(tty)) {
-                       set_bit(INTR_CHAR(tty), tty->process_char_map);
-                       set_bit(QUIT_CHAR(tty), tty->process_char_map);
-                       set_bit(SUSP_CHAR(tty), tty->process_char_map);
-               }
-               clear_bit(__DISABLED_CHAR, tty->process_char_map);
-               tty->raw = 0;
-               tty->real_raw = 0;
-       } else {
-               tty->raw = 1;
-               if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
-                   (I_IGNPAR(tty) || !I_INPCK(tty)) &&
-                   (tty->driver->flags & TTY_DRIVER_REAL_RAW))
-                       tty->real_raw = 1;
-               else
-                       tty->real_raw = 0;
-       }
-       n_tty_set_room(tty);
-       /* The termios change make the tty ready for I/O */
-       wake_up_interruptible(&tty->write_wait);
-       wake_up_interruptible(&tty->read_wait);
-}
-
-/**
- *     n_tty_close             -       close the ldisc for this tty
- *     @tty: device
- *
- *     Called from the terminal layer when this line discipline is
- *     being shut down, either because of a close or becsuse of a
- *     discipline change. The function will not be called while other
- *     ldisc methods are in progress.
- */
-
-static void n_tty_close(struct tty_struct *tty)
-{
-       n_tty_flush_buffer(tty);
-       if (tty->read_buf) {
-               kfree(tty->read_buf);
-               tty->read_buf = NULL;
-       }
-       if (tty->echo_buf) {
-               kfree(tty->echo_buf);
-               tty->echo_buf = NULL;
-       }
-}
-
-/**
- *     n_tty_open              -       open an ldisc
- *     @tty: terminal to open
- *
- *     Called when this line discipline is being attached to the
- *     terminal device. Can sleep. Called serialized so that no
- *     other events will occur in parallel. No further open will occur
- *     until a close.
- */
-
-static int n_tty_open(struct tty_struct *tty)
-{
-       if (!tty)
-               return -EINVAL;
-
-       /* These are ugly. Currently a malloc failure here can panic */
-       if (!tty->read_buf) {
-               tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
-               if (!tty->read_buf)
-                       return -ENOMEM;
-       }
-       if (!tty->echo_buf) {
-               tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
-
-               if (!tty->echo_buf)
-                       return -ENOMEM;
-       }
-       reset_buffer_flags(tty);
-       tty->column = 0;
-       n_tty_set_termios(tty, NULL);
-       tty->minimum_to_wake = 1;
-       tty->closing = 0;
-       return 0;
-}
-
-static inline int input_available_p(struct tty_struct *tty, int amt)
-{
-       tty_flush_to_ldisc(tty);
-       if (tty->icanon && !L_EXTPROC(tty)) {
-               if (tty->canon_data)
-                       return 1;
-       } else if (tty->read_cnt >= (amt ? amt : 1))
-               return 1;
-
-       return 0;
-}
-
-/**
- *     copy_from_read_buf      -       copy read data directly
- *     @tty: terminal device
- *     @b: user data
- *     @nr: size of data
- *
- *     Helper function to speed up n_tty_read.  It is only called when
- *     ICANON is off; it copies characters straight from the tty queue to
- *     user space directly.  It can be profitably called twice; once to
- *     drain the space from the tail pointer to the (physical) end of the
- *     buffer, and once to drain the space from the (physical) beginning of
- *     the buffer to head pointer.
- *
- *     Called under the tty->atomic_read_lock sem
- *
- */
-
-static int copy_from_read_buf(struct tty_struct *tty,
-                                     unsigned char __user **b,
-                                     size_t *nr)
-
-{
-       int retval;
-       size_t n;
-       unsigned long flags;
-
-       retval = 0;
-       spin_lock_irqsave(&tty->read_lock, flags);
-       n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail);
-       n = min(*nr, n);
-       spin_unlock_irqrestore(&tty->read_lock, flags);
-       if (n) {
-               retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
-               n -= retval;
-               tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
-               spin_lock_irqsave(&tty->read_lock, flags);
-               tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
-               tty->read_cnt -= n;
-               /* Turn single EOF into zero-length read */
-               if (L_EXTPROC(tty) && tty->icanon && n == 1) {
-                       if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
-                               n--;
-               }
-               spin_unlock_irqrestore(&tty->read_lock, flags);
-               *b += n;
-               *nr -= n;
-       }
-       return retval;
-}
-
-extern ssize_t redirected_tty_write(struct file *, const char __user *,
-                                                       size_t, loff_t *);
-
-/**
- *     job_control             -       check job control
- *     @tty: tty
- *     @file: file handle
- *
- *     Perform job control management checks on this file/tty descriptor
- *     and if appropriate send any needed signals and return a negative
- *     error code if action should be taken.
- *
- *     FIXME:
- *     Locking: None - redirected write test is safe, testing
- *     current->signal should possibly lock current->sighand
- *     pgrp locking ?
- */
-
-static int job_control(struct tty_struct *tty, struct file *file)
-{
-       /* Job control check -- must be done at start and after
-          every sleep (POSIX.1 7.1.1.4). */
-       /* NOTE: not yet done after every sleep pending a thorough
-          check of the logic of this change. -- jlc */
-       /* don't stop on /dev/console */
-       if (file->f_op->write != redirected_tty_write &&
-           current->signal->tty == tty) {
-               if (!tty->pgrp)
-                       printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
-               else if (task_pgrp(current) != tty->pgrp) {
-                       if (is_ignored(SIGTTIN) ||
-                           is_current_pgrp_orphaned())
-                               return -EIO;
-                       kill_pgrp(task_pgrp(current), SIGTTIN, 1);
-                       set_thread_flag(TIF_SIGPENDING);
-                       return -ERESTARTSYS;
-               }
-       }
-       return 0;
-}
-
-
-/**
- *     n_tty_read              -       read function for tty
- *     @tty: tty device
- *     @file: file object
- *     @buf: userspace buffer pointer
- *     @nr: size of I/O
- *
- *     Perform reads for the line discipline. We are guaranteed that the
- *     line discipline will not be closed under us but we may get multiple
- *     parallel readers and must handle this ourselves. We may also get
- *     a hangup. Always called in user context, may sleep.
- *
- *     This code must be sure never to sleep through a hangup.
- */
-
-static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
-                        unsigned char __user *buf, size_t nr)
-{
-       unsigned char __user *b = buf;
-       DECLARE_WAITQUEUE(wait, current);
-       int c;
-       int minimum, time;
-       ssize_t retval = 0;
-       ssize_t size;
-       long timeout;
-       unsigned long flags;
-       int packet;
-
-do_it_again:
-
-       BUG_ON(!tty->read_buf);
-
-       c = job_control(tty, file);
-       if (c < 0)
-               return c;
-
-       minimum = time = 0;
-       timeout = MAX_SCHEDULE_TIMEOUT;
-       if (!tty->icanon) {
-               time = (HZ / 10) * TIME_CHAR(tty);
-               minimum = MIN_CHAR(tty);
-               if (minimum) {
-                       if (time)
-                               tty->minimum_to_wake = 1;
-                       else if (!waitqueue_active(&tty->read_wait) ||
-                                (tty->minimum_to_wake > minimum))
-                               tty->minimum_to_wake = minimum;
-               } else {
-                       timeout = 0;
-                       if (time) {
-                               timeout = time;
-                               time = 0;
-                       }
-                       tty->minimum_to_wake = minimum = 1;
-               }
-       }
-
-       /*
-        *      Internal serialization of reads.
-        */
-       if (file->f_flags & O_NONBLOCK) {
-               if (!mutex_trylock(&tty->atomic_read_lock))
-                       return -EAGAIN;
-       } else {
-               if (mutex_lock_interruptible(&tty->atomic_read_lock))
-                       return -ERESTARTSYS;
-       }
-       packet = tty->packet;
-
-       add_wait_queue(&tty->read_wait, &wait);
-       while (nr) {
-               /* First test for status change. */
-               if (packet && tty->link->ctrl_status) {
-                       unsigned char cs;
-                       if (b != buf)
-                               break;
-                       spin_lock_irqsave(&tty->link->ctrl_lock, flags);
-                       cs = tty->link->ctrl_status;
-                       tty->link->ctrl_status = 0;
-                       spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
-                       if (tty_put_user(tty, cs, b++)) {
-                               retval = -EFAULT;
-                               b--;
-                               break;
-                       }
-                       nr--;
-                       break;
-               }
-               /* This statement must be first before checking for input
-                  so that any interrupt will set the state back to
-                  TASK_RUNNING. */
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
-                   ((minimum - (b - buf)) >= 1))
-                       tty->minimum_to_wake = (minimum - (b - buf));
-
-               if (!input_available_p(tty, 0)) {
-                       if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
-                               retval = -EIO;
-                               break;
-                       }
-                       if (tty_hung_up_p(file))
-                               break;
-                       if (!timeout)
-                               break;
-                       if (file->f_flags & O_NONBLOCK) {
-                               retval = -EAGAIN;
-                               break;
-                       }
-                       if (signal_pending(current)) {
-                               retval = -ERESTARTSYS;
-                               break;
-                       }
-                       /* FIXME: does n_tty_set_room need locking ? */
-                       n_tty_set_room(tty);
-                       timeout = schedule_timeout(timeout);
-                       continue;
-               }
-               __set_current_state(TASK_RUNNING);
-
-               /* Deal with packet mode. */
-               if (packet && b == buf) {
-                       if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
-                               retval = -EFAULT;
-                               b--;
-                               break;
-                       }
-                       nr--;
-               }
-
-               if (tty->icanon && !L_EXTPROC(tty)) {
-                       /* N.B. avoid overrun if nr == 0 */
-                       while (nr && tty->read_cnt) {
-                               int eol;
-
-                               eol = test_and_clear_bit(tty->read_tail,
-                                               tty->read_flags);
-                               c = tty->read_buf[tty->read_tail];
-                               spin_lock_irqsave(&tty->read_lock, flags);
-                               tty->read_tail = ((tty->read_tail+1) &
-                                                 (N_TTY_BUF_SIZE-1));
-                               tty->read_cnt--;
-                               if (eol) {
-                                       /* this test should be redundant:
-                                        * we shouldn't be reading data if
-                                        * canon_data is 0
-                                        */
-                                       if (--tty->canon_data < 0)
-                                               tty->canon_data = 0;
-                               }
-                               spin_unlock_irqrestore(&tty->read_lock, flags);
-
-                               if (!eol || (c != __DISABLED_CHAR)) {
-                                       if (tty_put_user(tty, c, b++)) {
-                                               retval = -EFAULT;
-                                               b--;
-                                               break;
-                                       }
-                                       nr--;
-                               }
-                               if (eol) {
-                                       tty_audit_push(tty);
-                                       break;
-                               }
-                       }
-                       if (retval)
-                               break;
-               } else {
-                       int uncopied;
-                       /* The copy function takes the read lock and handles
-                          locking internally for this case */
-                       uncopied = copy_from_read_buf(tty, &b, &nr);
-                       uncopied += copy_from_read_buf(tty, &b, &nr);
-                       if (uncopied) {
-                               retval = -EFAULT;
-                               break;
-                       }
-               }
-
-               /* If there is enough space in the read buffer now, let the
-                * low-level driver know. We use n_tty_chars_in_buffer() to
-                * check the buffer, as it now knows about canonical mode.
-                * Otherwise, if the driver is throttled and the line is
-                * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
-                * we won't get any more characters.
-                */
-               if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
-                       n_tty_set_room(tty);
-                       check_unthrottle(tty);
-               }
-
-               if (b - buf >= minimum)
-                       break;
-               if (time)
-                       timeout = time;
-       }
-       mutex_unlock(&tty->atomic_read_lock);
-       remove_wait_queue(&tty->read_wait, &wait);
-
-       if (!waitqueue_active(&tty->read_wait))
-               tty->minimum_to_wake = minimum;
-
-       __set_current_state(TASK_RUNNING);
-       size = b - buf;
-       if (size) {
-               retval = size;
-               if (nr)
-                       clear_bit(TTY_PUSH, &tty->flags);
-       } else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
-                goto do_it_again;
-
-       n_tty_set_room(tty);
-       return retval;
-}
-
-/**
- *     n_tty_write             -       write function for tty
- *     @tty: tty device
- *     @file: file object
- *     @buf: userspace buffer pointer
- *     @nr: size of I/O
- *
- *     Write function of the terminal device.  This is serialized with
- *     respect to other write callers but not to termios changes, reads
- *     and other such events.  Since the receive code will echo characters,
- *     thus calling driver write methods, the output_lock is used in
- *     the output processing functions called here as well as in the
- *     echo processing function to protect the column state and space
- *     left in the buffer.
- *
- *     This code must be sure never to sleep through a hangup.
- *
- *     Locking: output_lock to protect column state and space left
- *              (note that the process_output*() functions take this
- *               lock themselves)
- */
-
-static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
-                          const unsigned char *buf, size_t nr)
-{
-       const unsigned char *b = buf;
-       DECLARE_WAITQUEUE(wait, current);
-       int c;
-       ssize_t retval = 0;
-
-       /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
-       if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
-               retval = tty_check_change(tty);
-               if (retval)
-                       return retval;
-       }
-
-       /* Write out any echoed characters that are still pending */
-       process_echoes(tty);
-
-       add_wait_queue(&tty->write_wait, &wait);
-       while (1) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
-                       retval = -EIO;
-                       break;
-               }
-               if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
-                       while (nr > 0) {
-                               ssize_t num = process_output_block(tty, b, nr);
-                               if (num < 0) {
-                                       if (num == -EAGAIN)
-                                               break;
-                                       retval = num;
-                                       goto break_out;
-                               }
-                               b += num;
-                               nr -= num;
-                               if (nr == 0)
-                                       break;
-                               c = *b;
-                               if (process_output(c, tty) < 0)
-                                       break;
-                               b++; nr--;
-                       }
-                       if (tty->ops->flush_chars)
-                               tty->ops->flush_chars(tty);
-               } else {
-                       while (nr > 0) {
-                               c = tty->ops->write(tty, b, nr);
-                               if (c < 0) {
-                                       retval = c;
-                                       goto break_out;
-                               }
-                               if (!c)
-                                       break;
-                               b += c;
-                               nr -= c;
-                       }
-               }
-               if (!nr)
-                       break;
-               if (file->f_flags & O_NONBLOCK) {
-                       retval = -EAGAIN;
-                       break;
-               }
-               schedule();
-       }
-break_out:
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&tty->write_wait, &wait);
-       if (b - buf != nr && tty->fasync)
-               set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-       return (b - buf) ? b - buf : retval;
-}
-
-/**
- *     n_tty_poll              -       poll method for N_TTY
- *     @tty: terminal device
- *     @file: file accessing it
- *     @wait: poll table
- *
- *     Called when the line discipline is asked to poll() for data or
- *     for special events. This code is not serialized with respect to
- *     other events save open/close.
- *
- *     This code must be sure never to sleep through a hangup.
- *     Called without the kernel lock held - fine
- */
-
-static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
-                                                       poll_table *wait)
-{
-       unsigned int mask = 0;
-
-       poll_wait(file, &tty->read_wait, wait);
-       poll_wait(file, &tty->write_wait, wait);
-       if (input_available_p(tty, TIME_CHAR(tty) ? 0 : MIN_CHAR(tty)))
-               mask |= POLLIN | POLLRDNORM;
-       if (tty->packet && tty->link->ctrl_status)
-               mask |= POLLPRI | POLLIN | POLLRDNORM;
-       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
-               mask |= POLLHUP;
-       if (tty_hung_up_p(file))
-               mask |= POLLHUP;
-       if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
-               if (MIN_CHAR(tty) && !TIME_CHAR(tty))
-                       tty->minimum_to_wake = MIN_CHAR(tty);
-               else
-                       tty->minimum_to_wake = 1;
-       }
-       if (tty->ops->write && !tty_is_writelocked(tty) &&
-                       tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
-                       tty_write_room(tty) > 0)
-               mask |= POLLOUT | POLLWRNORM;
-       return mask;
-}
-
-static unsigned long inq_canon(struct tty_struct *tty)
-{
-       int nr, head, tail;
-
-       if (!tty->canon_data)
-               return 0;
-       head = tty->canon_head;
-       tail = tty->read_tail;
-       nr = (head - tail) & (N_TTY_BUF_SIZE-1);
-       /* Skip EOF-chars.. */
-       while (head != tail) {
-               if (test_bit(tail, tty->read_flags) &&
-                   tty->read_buf[tail] == __DISABLED_CHAR)
-                       nr--;
-               tail = (tail+1) & (N_TTY_BUF_SIZE-1);
-       }
-       return nr;
-}
-
-static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       int retval;
-
-       switch (cmd) {
-       case TIOCOUTQ:
-               return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
-       case TIOCINQ:
-               /* FIXME: Locking */
-               retval = tty->read_cnt;
-               if (L_ICANON(tty))
-                       retval = inq_canon(tty);
-               return put_user(retval, (unsigned int __user *) arg);
-       default:
-               return n_tty_ioctl_helper(tty, file, cmd, arg);
-       }
-}
-
-struct tty_ldisc_ops tty_ldisc_N_TTY = {
-       .magic           = TTY_LDISC_MAGIC,
-       .name            = "n_tty",
-       .open            = n_tty_open,
-       .close           = n_tty_close,
-       .flush_buffer    = n_tty_flush_buffer,
-       .chars_in_buffer = n_tty_chars_in_buffer,
-       .read            = n_tty_read,
-       .write           = n_tty_write,
-       .ioctl           = n_tty_ioctl,
-       .set_termios     = n_tty_set_termios,
-       .poll            = n_tty_poll,
-       .receive_buf     = n_tty_receive_buf,
-       .write_wakeup    = n_tty_write_wakeup
-};
-
-/**
- *     n_tty_inherit_ops       -       inherit N_TTY methods
- *     @ops: struct tty_ldisc_ops where to save N_TTY methods
- *
- *     Used by a generic struct tty_ldisc_ops to easily inherit N_TTY
- *     methods.
- */
-
-void n_tty_inherit_ops(struct tty_ldisc_ops *ops)
-{
-       *ops = tty_ldisc_N_TTY;
-       ops->owner = NULL;
-       ops->refcount = ops->flags = 0;
-}
-EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
deleted file mode 100644 (file)
index 923a485..0000000
+++ /dev/null
@@ -1,777 +0,0 @@
-/*
- *  linux/drivers/char/pty.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- *  Added support for a Unix98-style ptmx device.
- *    -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
- *
- *  When reading this code see also fs/devpts. In particular note that the
- *  driver_data field is used by the devpts side as a binding to the devpts
- *  inode.
- */
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/sysctl.h>
-#include <linux/device.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/devpts_fs.h>
-#include <linux/slab.h>
-
-#include <asm/system.h>
-
-#ifdef CONFIG_UNIX98_PTYS
-static struct tty_driver *ptm_driver;
-static struct tty_driver *pts_driver;
-#endif
-
-static void pty_close(struct tty_struct *tty, struct file *filp)
-{
-       BUG_ON(!tty);
-       if (tty->driver->subtype == PTY_TYPE_MASTER)
-               WARN_ON(tty->count > 1);
-       else {
-               if (tty->count > 2)
-                       return;
-       }
-       wake_up_interruptible(&tty->read_wait);
-       wake_up_interruptible(&tty->write_wait);
-       tty->packet = 0;
-       if (!tty->link)
-               return;
-       tty->link->packet = 0;
-       set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
-       wake_up_interruptible(&tty->link->read_wait);
-       wake_up_interruptible(&tty->link->write_wait);
-       if (tty->driver->subtype == PTY_TYPE_MASTER) {
-               set_bit(TTY_OTHER_CLOSED, &tty->flags);
-#ifdef CONFIG_UNIX98_PTYS
-               if (tty->driver == ptm_driver)
-                       devpts_pty_kill(tty->link);
-#endif
-               tty_unlock();
-               tty_vhangup(tty->link);
-               tty_lock();
-       }
-}
-
-/*
- * The unthrottle routine is called by the line discipline to signal
- * that it can receive more characters.  For PTY's, the TTY_THROTTLED
- * flag is always set, to force the line discipline to always call the
- * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
- * characters in the queue.  This is necessary since each time this
- * happens, we need to wake up any sleeping processes that could be
- * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
- * for the pty buffer to be drained.
- */
-static void pty_unthrottle(struct tty_struct *tty)
-{
-       tty_wakeup(tty->link);
-       set_bit(TTY_THROTTLED, &tty->flags);
-}
-
-/**
- *     pty_space       -       report space left for writing
- *     @to: tty we are writing into
- *
- *     The tty buffers allow 64K but we sneak a peak and clip at 8K this
- *     allows a lot of overspill room for echo and other fun messes to
- *     be handled properly
- */
-
-static int pty_space(struct tty_struct *to)
-{
-       int n = 8192 - to->buf.memory_used;
-       if (n < 0)
-               return 0;
-       return n;
-}
-
-/**
- *     pty_write               -       write to a pty
- *     @tty: the tty we write from
- *     @buf: kernel buffer of data
- *     @count: bytes to write
- *
- *     Our "hardware" write method. Data is coming from the ldisc which
- *     may be in a non sleeping state. We simply throw this at the other
- *     end of the link as if we were an IRQ handler receiving stuff for
- *     the other side of the pty/tty pair.
- */
-
-static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
-{
-       struct tty_struct *to = tty->link;
-
-       if (tty->stopped)
-               return 0;
-
-       if (c > 0) {
-               /* Stuff the data into the input queue of the other end */
-               c = tty_insert_flip_string(to, buf, c);
-               /* And shovel */
-               if (c) {
-                       tty_flip_buffer_push(to);
-                       tty_wakeup(tty);
-               }
-       }
-       return c;
-}
-
-/**
- *     pty_write_room  -       write space
- *     @tty: tty we are writing from
- *
- *     Report how many bytes the ldisc can send into the queue for
- *     the other device.
- */
-
-static int pty_write_room(struct tty_struct *tty)
-{
-       if (tty->stopped)
-               return 0;
-       return pty_space(tty->link);
-}
-
-/**
- *     pty_chars_in_buffer     -       characters currently in our tx queue
- *     @tty: our tty
- *
- *     Report how much we have in the transmit queue. As everything is
- *     instantly at the other end this is easy to implement.
- */
-
-static int pty_chars_in_buffer(struct tty_struct *tty)
-{
-       return 0;
-}
-
-/* Set the lock flag on a pty */
-static int pty_set_lock(struct tty_struct *tty, int __user *arg)
-{
-       int val;
-       if (get_user(val, arg))
-               return -EFAULT;
-       if (val)
-               set_bit(TTY_PTY_LOCK, &tty->flags);
-       else
-               clear_bit(TTY_PTY_LOCK, &tty->flags);
-       return 0;
-}
-
-/* Send a signal to the slave */
-static int pty_signal(struct tty_struct *tty, int sig)
-{
-       unsigned long flags;
-       struct pid *pgrp;
-
-       if (tty->link) {
-               spin_lock_irqsave(&tty->link->ctrl_lock, flags);
-               pgrp = get_pid(tty->link->pgrp);
-               spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
-
-               kill_pgrp(pgrp, sig, 1);
-               put_pid(pgrp);
-       }
-       return 0;
-}
-
-static void pty_flush_buffer(struct tty_struct *tty)
-{
-       struct tty_struct *to = tty->link;
-       unsigned long flags;
-
-       if (!to)
-               return;
-       /* tty_buffer_flush(to); FIXME */
-       if (to->packet) {
-               spin_lock_irqsave(&tty->ctrl_lock, flags);
-               tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
-               wake_up_interruptible(&to->read_wait);
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-       }
-}
-
-static int pty_open(struct tty_struct *tty, struct file *filp)
-{
-       int     retval = -ENODEV;
-
-       if (!tty || !tty->link)
-               goto out;
-
-       retval = -EIO;
-       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
-               goto out;
-       if (test_bit(TTY_PTY_LOCK, &tty->link->flags))
-               goto out;
-       if (tty->link->count != 1)
-               goto out;
-
-       clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
-       set_bit(TTY_THROTTLED, &tty->flags);
-       retval = 0;
-out:
-       return retval;
-}
-
-static void pty_set_termios(struct tty_struct *tty,
-                                       struct ktermios *old_termios)
-{
-       tty->termios->c_cflag &= ~(CSIZE | PARENB);
-       tty->termios->c_cflag |= (CS8 | CREAD);
-}
-
-/**
- *     pty_do_resize           -       resize event
- *     @tty: tty being resized
- *     @ws: window size being set.
- *
- *     Update the termios variables and send the necessary signals to
- *     peform a terminal resize correctly
- */
-
-int pty_resize(struct tty_struct *tty,  struct winsize *ws)
-{
-       struct pid *pgrp, *rpgrp;
-       unsigned long flags;
-       struct tty_struct *pty = tty->link;
-
-       /* For a PTY we need to lock the tty side */
-       mutex_lock(&tty->termios_mutex);
-       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
-               goto done;
-
-       /* Get the PID values and reference them so we can
-          avoid holding the tty ctrl lock while sending signals.
-          We need to lock these individually however. */
-
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       pgrp = get_pid(tty->pgrp);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-       spin_lock_irqsave(&pty->ctrl_lock, flags);
-       rpgrp = get_pid(pty->pgrp);
-       spin_unlock_irqrestore(&pty->ctrl_lock, flags);
-
-       if (pgrp)
-               kill_pgrp(pgrp, SIGWINCH, 1);
-       if (rpgrp != pgrp && rpgrp)
-               kill_pgrp(rpgrp, SIGWINCH, 1);
-
-       put_pid(pgrp);
-       put_pid(rpgrp);
-
-       tty->winsize = *ws;
-       pty->winsize = *ws;     /* Never used so will go away soon */
-done:
-       mutex_unlock(&tty->termios_mutex);
-       return 0;
-}
-
-/* Traditional BSD devices */
-#ifdef CONFIG_LEGACY_PTYS
-
-static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
-{
-       struct tty_struct *o_tty;
-       int idx = tty->index;
-       int retval;
-
-       o_tty = alloc_tty_struct();
-       if (!o_tty)
-               return -ENOMEM;
-       if (!try_module_get(driver->other->owner)) {
-               /* This cannot in fact currently happen */
-               free_tty_struct(o_tty);
-               return -ENOMEM;
-       }
-       initialize_tty_struct(o_tty, driver->other, idx);
-
-       /* We always use new tty termios data so we can do this
-          the easy way .. */
-       retval = tty_init_termios(tty);
-       if (retval)
-               goto free_mem_out;
-
-       retval = tty_init_termios(o_tty);
-       if (retval) {
-               tty_free_termios(tty);
-               goto free_mem_out;
-       }
-
-       /*
-        * Everything allocated ... set up the o_tty structure.
-        */
-       driver->other->ttys[idx] = o_tty;
-       tty_driver_kref_get(driver->other);
-       if (driver->subtype == PTY_TYPE_MASTER)
-               o_tty->count++;
-       /* Establish the links in both directions */
-       tty->link   = o_tty;
-       o_tty->link = tty;
-
-       tty_driver_kref_get(driver);
-       tty->count++;
-       driver->ttys[idx] = tty;
-       return 0;
-free_mem_out:
-       module_put(o_tty->driver->owner);
-       free_tty_struct(o_tty);
-       return -ENOMEM;
-}
-
-static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
-                        unsigned int cmd, unsigned long arg)
-{
-       switch (cmd) {
-       case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
-               return pty_set_lock(tty, (int __user *) arg);
-       case TIOCSIG:    /* Send signal to other side of pty */
-               return pty_signal(tty, (int) arg);
-       }
-       return -ENOIOCTLCMD;
-}
-
-static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
-module_param(legacy_count, int, 0);
-
-/*
- * The master side of a pty can do TIOCSPTLCK and thus
- * has pty_bsd_ioctl.
- */
-static const struct tty_operations master_pty_ops_bsd = {
-       .install = pty_install,
-       .open = pty_open,
-       .close = pty_close,
-       .write = pty_write,
-       .write_room = pty_write_room,
-       .flush_buffer = pty_flush_buffer,
-       .chars_in_buffer = pty_chars_in_buffer,
-       .unthrottle = pty_unthrottle,
-       .set_termios = pty_set_termios,
-       .ioctl = pty_bsd_ioctl,
-       .resize = pty_resize
-};
-
-static const struct tty_operations slave_pty_ops_bsd = {
-       .install = pty_install,
-       .open = pty_open,
-       .close = pty_close,
-       .write = pty_write,
-       .write_room = pty_write_room,
-       .flush_buffer = pty_flush_buffer,
-       .chars_in_buffer = pty_chars_in_buffer,
-       .unthrottle = pty_unthrottle,
-       .set_termios = pty_set_termios,
-       .resize = pty_resize
-};
-
-static void __init legacy_pty_init(void)
-{
-       struct tty_driver *pty_driver, *pty_slave_driver;
-
-       if (legacy_count <= 0)
-               return;
-
-       pty_driver = alloc_tty_driver(legacy_count);
-       if (!pty_driver)
-               panic("Couldn't allocate pty driver");
-
-       pty_slave_driver = alloc_tty_driver(legacy_count);
-       if (!pty_slave_driver)
-               panic("Couldn't allocate pty slave driver");
-
-       pty_driver->owner = THIS_MODULE;
-       pty_driver->driver_name = "pty_master";
-       pty_driver->name = "pty";
-       pty_driver->major = PTY_MASTER_MAJOR;
-       pty_driver->minor_start = 0;
-       pty_driver->type = TTY_DRIVER_TYPE_PTY;
-       pty_driver->subtype = PTY_TYPE_MASTER;
-       pty_driver->init_termios = tty_std_termios;
-       pty_driver->init_termios.c_iflag = 0;
-       pty_driver->init_termios.c_oflag = 0;
-       pty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-       pty_driver->init_termios.c_lflag = 0;
-       pty_driver->init_termios.c_ispeed = 38400;
-       pty_driver->init_termios.c_ospeed = 38400;
-       pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
-       pty_driver->other = pty_slave_driver;
-       tty_set_operations(pty_driver, &master_pty_ops_bsd);
-
-       pty_slave_driver->owner = THIS_MODULE;
-       pty_slave_driver->driver_name = "pty_slave";
-       pty_slave_driver->name = "ttyp";
-       pty_slave_driver->major = PTY_SLAVE_MAJOR;
-       pty_slave_driver->minor_start = 0;
-       pty_slave_driver->type = TTY_DRIVER_TYPE_PTY;
-       pty_slave_driver->subtype = PTY_TYPE_SLAVE;
-       pty_slave_driver->init_termios = tty_std_termios;
-       pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-       pty_slave_driver->init_termios.c_ispeed = 38400;
-       pty_slave_driver->init_termios.c_ospeed = 38400;
-       pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS |
-                                       TTY_DRIVER_REAL_RAW;
-       pty_slave_driver->other = pty_driver;
-       tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);
-
-       if (tty_register_driver(pty_driver))
-               panic("Couldn't register pty driver");
-       if (tty_register_driver(pty_slave_driver))
-               panic("Couldn't register pty slave driver");
-}
-#else
-static inline void legacy_pty_init(void) { }
-#endif
-
-/* Unix98 devices */
-#ifdef CONFIG_UNIX98_PTYS
-/*
- * sysctl support for setting limits on the number of Unix98 ptys allocated.
- * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
- */
-int pty_limit = NR_UNIX98_PTY_DEFAULT;
-static int pty_limit_min;
-static int pty_limit_max = NR_UNIX98_PTY_MAX;
-static int pty_count;
-
-static struct cdev ptmx_cdev;
-
-static struct ctl_table pty_table[] = {
-       {
-               .procname       = "max",
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .data           = &pty_limit,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &pty_limit_min,
-               .extra2         = &pty_limit_max,
-       }, {
-               .procname       = "nr",
-               .maxlen         = sizeof(int),
-               .mode           = 0444,
-               .data           = &pty_count,
-               .proc_handler   = proc_dointvec,
-       }, 
-       {}
-};
-
-static struct ctl_table pty_kern_table[] = {
-       {
-               .procname       = "pty",
-               .mode           = 0555,
-               .child          = pty_table,
-       },
-       {}
-};
-
-static struct ctl_table pty_root_table[] = {
-       {
-               .procname       = "kernel",
-               .mode           = 0555,
-               .child          = pty_kern_table,
-       },
-       {}
-};
-
-
-static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
-                           unsigned int cmd, unsigned long arg)
-{
-       switch (cmd) {
-       case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
-               return pty_set_lock(tty, (int __user *)arg);
-       case TIOCGPTN: /* Get PT Number */
-               return put_user(tty->index, (unsigned int __user *)arg);
-       case TIOCSIG:    /* Send signal to other side of pty */
-               return pty_signal(tty, (int) arg);
-       }
-
-       return -ENOIOCTLCMD;
-}
-
-/**
- *     ptm_unix98_lookup       -       find a pty master
- *     @driver: ptm driver
- *     @idx: tty index
- *
- *     Look up a pty master device. Called under the tty_mutex for now.
- *     This provides our locking.
- */
-
-static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
-               struct inode *ptm_inode, int idx)
-{
-       struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
-       if (tty)
-               tty = tty->link;
-       return tty;
-}
-
-/**
- *     pts_unix98_lookup       -       find a pty slave
- *     @driver: pts driver
- *     @idx: tty index
- *
- *     Look up a pty master device. Called under the tty_mutex for now.
- *     This provides our locking.
- */
-
-static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
-               struct inode *pts_inode, int idx)
-{
-       struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
-       /* Master must be open before slave */
-       if (!tty)
-               return ERR_PTR(-EIO);
-       return tty;
-}
-
-static void pty_unix98_shutdown(struct tty_struct *tty)
-{
-       /* We have our own method as we don't use the tty index */
-       kfree(tty->termios);
-}
-
-/* We have no need to install and remove our tty objects as devpts does all
-   the work for us */
-
-static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
-{
-       struct tty_struct *o_tty;
-       int idx = tty->index;
-
-       o_tty = alloc_tty_struct();
-       if (!o_tty)
-               return -ENOMEM;
-       if (!try_module_get(driver->other->owner)) {
-               /* This cannot in fact currently happen */
-               free_tty_struct(o_tty);
-               return -ENOMEM;
-       }
-       initialize_tty_struct(o_tty, driver->other, idx);
-
-       tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-       if (tty->termios == NULL)
-               goto free_mem_out;
-       *tty->termios = driver->init_termios;
-       tty->termios_locked = tty->termios + 1;
-
-       o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-       if (o_tty->termios == NULL)
-               goto free_mem_out;
-       *o_tty->termios = driver->other->init_termios;
-       o_tty->termios_locked = o_tty->termios + 1;
-
-       tty_driver_kref_get(driver->other);
-       if (driver->subtype == PTY_TYPE_MASTER)
-               o_tty->count++;
-       /* Establish the links in both directions */
-       tty->link   = o_tty;
-       o_tty->link = tty;
-       /*
-        * All structures have been allocated, so now we install them.
-        * Failures after this point use release_tty to clean up, so
-        * there's no need to null out the local pointers.
-        */
-       tty_driver_kref_get(driver);
-       tty->count++;
-       pty_count++;
-       return 0;
-free_mem_out:
-       kfree(o_tty->termios);
-       module_put(o_tty->driver->owner);
-       free_tty_struct(o_tty);
-       kfree(tty->termios);
-       return -ENOMEM;
-}
-
-static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
-{
-       pty_count--;
-}
-
-static const struct tty_operations ptm_unix98_ops = {
-       .lookup = ptm_unix98_lookup,
-       .install = pty_unix98_install,
-       .remove = pty_unix98_remove,
-       .open = pty_open,
-       .close = pty_close,
-       .write = pty_write,
-       .write_room = pty_write_room,
-       .flush_buffer = pty_flush_buffer,
-       .chars_in_buffer = pty_chars_in_buffer,
-       .unthrottle = pty_unthrottle,
-       .set_termios = pty_set_termios,
-       .ioctl = pty_unix98_ioctl,
-       .shutdown = pty_unix98_shutdown,
-       .resize = pty_resize
-};
-
-static const struct tty_operations pty_unix98_ops = {
-       .lookup = pts_unix98_lookup,
-       .install = pty_unix98_install,
-       .remove = pty_unix98_remove,
-       .open = pty_open,
-       .close = pty_close,
-       .write = pty_write,
-       .write_room = pty_write_room,
-       .flush_buffer = pty_flush_buffer,
-       .chars_in_buffer = pty_chars_in_buffer,
-       .unthrottle = pty_unthrottle,
-       .set_termios = pty_set_termios,
-       .shutdown = pty_unix98_shutdown
-};
-
-/**
- *     ptmx_open               -       open a unix 98 pty master
- *     @inode: inode of device file
- *     @filp: file pointer to tty
- *
- *     Allocate a unix98 pty master device from the ptmx driver.
- *
- *     Locking: tty_mutex protects the init_dev work. tty->count should
- *             protect the rest.
- *             allocated_ptys_lock handles the list of free pty numbers
- */
-
-static int ptmx_open(struct inode *inode, struct file *filp)
-{
-       struct tty_struct *tty;
-       int retval;
-       int index;
-
-       nonseekable_open(inode, filp);
-
-       /* find a device that is not in use. */
-       tty_lock();
-       index = devpts_new_index(inode);
-       tty_unlock();
-       if (index < 0)
-               return index;
-
-       mutex_lock(&tty_mutex);
-       tty_lock();
-       tty = tty_init_dev(ptm_driver, index, 1);
-       mutex_unlock(&tty_mutex);
-
-       if (IS_ERR(tty)) {
-               retval = PTR_ERR(tty);
-               goto out;
-       }
-
-       set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
-
-       retval = tty_add_file(tty, filp);
-       if (retval)
-               goto out;
-
-       retval = devpts_pty_new(inode, tty->link);
-       if (retval)
-               goto out1;
-
-       retval = ptm_driver->ops->open(tty, filp);
-       if (retval)
-               goto out2;
-out1:
-       tty_unlock();
-       return retval;
-out2:
-       tty_unlock();
-       tty_release(inode, filp);
-       return retval;
-out:
-       devpts_kill_index(inode, index);
-       tty_unlock();
-       return retval;
-}
-
-static struct file_operations ptmx_fops;
-
-static void __init unix98_pty_init(void)
-{
-       ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
-       if (!ptm_driver)
-               panic("Couldn't allocate Unix98 ptm driver");
-       pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
-       if (!pts_driver)
-               panic("Couldn't allocate Unix98 pts driver");
-
-       ptm_driver->owner = THIS_MODULE;
-       ptm_driver->driver_name = "pty_master";
-       ptm_driver->name = "ptm";
-       ptm_driver->major = UNIX98_PTY_MASTER_MAJOR;
-       ptm_driver->minor_start = 0;
-       ptm_driver->type = TTY_DRIVER_TYPE_PTY;
-       ptm_driver->subtype = PTY_TYPE_MASTER;
-       ptm_driver->init_termios = tty_std_termios;
-       ptm_driver->init_termios.c_iflag = 0;
-       ptm_driver->init_termios.c_oflag = 0;
-       ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-       ptm_driver->init_termios.c_lflag = 0;
-       ptm_driver->init_termios.c_ispeed = 38400;
-       ptm_driver->init_termios.c_ospeed = 38400;
-       ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
-               TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
-       ptm_driver->other = pts_driver;
-       tty_set_operations(ptm_driver, &ptm_unix98_ops);
-
-       pts_driver->owner = THIS_MODULE;
-       pts_driver->driver_name = "pty_slave";
-       pts_driver->name = "pts";
-       pts_driver->major = UNIX98_PTY_SLAVE_MAJOR;
-       pts_driver->minor_start = 0;
-       pts_driver->type = TTY_DRIVER_TYPE_PTY;
-       pts_driver->subtype = PTY_TYPE_SLAVE;
-       pts_driver->init_termios = tty_std_termios;
-       pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-       pts_driver->init_termios.c_ispeed = 38400;
-       pts_driver->init_termios.c_ospeed = 38400;
-       pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
-               TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
-       pts_driver->other = ptm_driver;
-       tty_set_operations(pts_driver, &pty_unix98_ops);
-
-       if (tty_register_driver(ptm_driver))
-               panic("Couldn't register Unix98 ptm driver");
-       if (tty_register_driver(pts_driver))
-               panic("Couldn't register Unix98 pts driver");
-
-       register_sysctl_table(pty_root_table);
-
-       /* Now create the /dev/ptmx special device */
-       tty_default_fops(&ptmx_fops);
-       ptmx_fops.open = ptmx_open;
-
-       cdev_init(&ptmx_cdev, &ptmx_fops);
-       if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
-           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
-               panic("Couldn't register /dev/ptmx driver\n");
-       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
-}
-
-#else
-static inline void unix98_pty_init(void) { }
-#endif
-
-static int __init pty_init(void)
-{
-       legacy_pty_init();
-       unix98_pty_init();
-       return 0;
-}
-module_init(pty_init);
diff --git a/drivers/char/selection.c b/drivers/char/selection.c
deleted file mode 100644 (file)
index ebae344..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * linux/drivers/char/selection.c
- *
- * This module exports the functions:
- *
- *     'int set_selection(struct tiocl_selection __user *, struct tty_struct *)'
- *     'void clear_selection(void)'
- *     'int paste_selection(struct tty_struct *)'
- *     'int sel_loadlut(char __user *)'
- *
- * Now that /dev/vcs exists, most of this can disappear again.
- */
-
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#include <asm/uaccess.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/consolemap.h>
-#include <linux/selection.h>
-#include <linux/tiocl.h>
-#include <linux/console.h>
-#include <linux/smp_lock.h>
-
-/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
-#define isspace(c)     ((c) == ' ')
-
-extern void poke_blanked_console(void);
-
-/* Variables for selection control. */
-/* Use a dynamic buffer, instead of static (Dec 1994) */
-struct vc_data *sel_cons;              /* must not be deallocated */
-static int use_unicode;
-static volatile int sel_start = -1;    /* cleared by clear_selection */
-static int sel_end;
-static int sel_buffer_lth;
-static char *sel_buffer;
-
-/* clear_selection, highlight and highlight_pointer can be called
-   from interrupt (via scrollback/front) */
-
-/* set reverse video on characters s-e of console with selection. */
-static inline void highlight(const int s, const int e)
-{
-       invert_screen(sel_cons, s, e-s+2, 1);
-}
-
-/* use complementary color to show the pointer */
-static inline void highlight_pointer(const int where)
-{
-       complement_pos(sel_cons, where);
-}
-
-static u16
-sel_pos(int n)
-{
-       return inverse_translate(sel_cons, screen_glyph(sel_cons, n),
-                               use_unicode);
-}
-
-/* remove the current selection highlight, if any,
-   from the console holding the selection. */
-void
-clear_selection(void) {
-       highlight_pointer(-1); /* hide the pointer */
-       if (sel_start != -1) {
-               highlight(sel_start, sel_end);
-               sel_start = -1;
-       }
-}
-
-/*
- * User settable table: what characters are to be considered alphabetic?
- * 256 bits
- */
-static u32 inwordLut[8]={
-  0x00000000, /* control chars     */
-  0x03FF0000, /* digits            */
-  0x87FFFFFE, /* uppercase and '_' */
-  0x07FFFFFE, /* lowercase         */
-  0x00000000,
-  0x00000000,
-  0xFF7FFFFF, /* latin-1 accented letters, not multiplication sign */
-  0xFF7FFFFF  /* latin-1 accented letters, not division sign */
-};
-
-static inline int inword(const u16 c) {
-       return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
-}
-
-/* set inwordLut contents. Invoked by ioctl(). */
-int sel_loadlut(char __user *p)
-{
-       return copy_from_user(inwordLut, (u32 __user *)(p+4), 32) ? -EFAULT : 0;
-}
-
-/* does screen address p correspond to character at LH/RH edge of screen? */
-static inline int atedge(const int p, int size_row)
-{
-       return (!(p % size_row) || !((p + 2) % size_row));
-}
-
-/* constrain v such that v <= u */
-static inline unsigned short limit(const unsigned short v, const unsigned short u)
-{
-       return (v > u) ? u : v;
-}
-
-/* stores the char in UTF8 and returns the number of bytes used (1-3) */
-static int store_utf8(u16 c, char *p)
-{
-       if (c < 0x80) {
-               /*  0******* */
-               p[0] = c;
-               return 1;
-       } else if (c < 0x800) {
-               /* 110***** 10****** */
-               p[0] = 0xc0 | (c >> 6);
-               p[1] = 0x80 | (c & 0x3f);
-               return 2;
-       } else {
-               /* 1110**** 10****** 10****** */
-               p[0] = 0xe0 | (c >> 12);
-               p[1] = 0x80 | ((c >> 6) & 0x3f);
-               p[2] = 0x80 | (c & 0x3f);
-               return 3;
-       }
-}
-
-/* set the current selection. Invoked by ioctl() or by kernel code. */
-int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-       int sel_mode, new_sel_start, new_sel_end, spc;
-       char *bp, *obp;
-       int i, ps, pe, multiplier;
-       u16 c;
-       struct kbd_struct *kbd = kbd_table + fg_console;
-
-       poke_blanked_console();
-
-       { unsigned short xs, ys, xe, ye;
-
-         if (!access_ok(VERIFY_READ, sel, sizeof(*sel)))
-               return -EFAULT;
-         __get_user(xs, &sel->xs);
-         __get_user(ys, &sel->ys);
-         __get_user(xe, &sel->xe);
-         __get_user(ye, &sel->ye);
-         __get_user(sel_mode, &sel->sel_mode);
-         xs--; ys--; xe--; ye--;
-         xs = limit(xs, vc->vc_cols - 1);
-         ys = limit(ys, vc->vc_rows - 1);
-         xe = limit(xe, vc->vc_cols - 1);
-         ye = limit(ye, vc->vc_rows - 1);
-         ps = ys * vc->vc_size_row + (xs << 1);
-         pe = ye * vc->vc_size_row + (xe << 1);
-
-         if (sel_mode == TIOCL_SELCLEAR) {
-             /* useful for screendump without selection highlights */
-             clear_selection();
-             return 0;
-         }
-
-         if (mouse_reporting() && (sel_mode & TIOCL_SELMOUSEREPORT)) {
-             mouse_report(tty, sel_mode & TIOCL_SELBUTTONMASK, xs, ys);
-             return 0;
-         }
-        }
-
-       if (ps > pe)    /* make sel_start <= sel_end */
-       {
-               int tmp = ps;
-               ps = pe;
-               pe = tmp;
-       }
-
-       if (sel_cons != vc_cons[fg_console].d) {
-               clear_selection();
-               sel_cons = vc_cons[fg_console].d;
-       }
-       use_unicode = kbd && kbd->kbdmode == VC_UNICODE;
-
-       switch (sel_mode)
-       {
-               case TIOCL_SELCHAR:     /* character-by-character selection */
-                       new_sel_start = ps;
-                       new_sel_end = pe;
-                       break;
-               case TIOCL_SELWORD:     /* word-by-word selection */
-                       spc = isspace(sel_pos(ps));
-                       for (new_sel_start = ps; ; ps -= 2)
-                       {
-                               if ((spc && !isspace(sel_pos(ps))) ||
-                                   (!spc && !inword(sel_pos(ps))))
-                                       break;
-                               new_sel_start = ps;
-                               if (!(ps % vc->vc_size_row))
-                                       break;
-                       }
-                       spc = isspace(sel_pos(pe));
-                       for (new_sel_end = pe; ; pe += 2)
-                       {
-                               if ((spc && !isspace(sel_pos(pe))) ||
-                                   (!spc && !inword(sel_pos(pe))))
-                                       break;
-                               new_sel_end = pe;
-                               if (!((pe + 2) % vc->vc_size_row))
-                                       break;
-                       }
-                       break;
-               case TIOCL_SELLINE:     /* line-by-line selection */
-                       new_sel_start = ps - ps % vc->vc_size_row;
-                       new_sel_end = pe + vc->vc_size_row
-                                   - pe % vc->vc_size_row - 2;
-                       break;
-               case TIOCL_SELPOINTER:
-                       highlight_pointer(pe);
-                       return 0;
-               default:
-                       return -EINVAL;
-       }
-
-       /* remove the pointer */
-       highlight_pointer(-1);
-
-       /* select to end of line if on trailing space */
-       if (new_sel_end > new_sel_start &&
-               !atedge(new_sel_end, vc->vc_size_row) &&
-               isspace(sel_pos(new_sel_end))) {
-               for (pe = new_sel_end + 2; ; pe += 2)
-                       if (!isspace(sel_pos(pe)) ||
-                           atedge(pe, vc->vc_size_row))
-                               break;
-               if (isspace(sel_pos(pe)))
-                       new_sel_end = pe;
-       }
-       if (sel_start == -1)    /* no current selection */
-               highlight(new_sel_start, new_sel_end);
-       else if (new_sel_start == sel_start)
-       {
-               if (new_sel_end == sel_end)     /* no action required */
-                       return 0;
-               else if (new_sel_end > sel_end) /* extend to right */
-                       highlight(sel_end + 2, new_sel_end);
-               else                            /* contract from right */
-                       highlight(new_sel_end + 2, sel_end);
-       }
-       else if (new_sel_end == sel_end)
-       {
-               if (new_sel_start < sel_start)  /* extend to left */
-                       highlight(new_sel_start, sel_start - 2);
-               else                            /* contract from left */
-                       highlight(sel_start, new_sel_start - 2);
-       }
-       else    /* some other case; start selection from scratch */
-       {
-               clear_selection();
-               highlight(new_sel_start, new_sel_end);
-       }
-       sel_start = new_sel_start;
-       sel_end = new_sel_end;
-
-       /* Allocate a new buffer before freeing the old one ... */
-       multiplier = use_unicode ? 3 : 1;  /* chars can take up to 3 bytes */
-       bp = kmalloc(((sel_end-sel_start)/2+1)*multiplier, GFP_KERNEL);
-       if (!bp) {
-               printk(KERN_WARNING "selection: kmalloc() failed\n");
-               clear_selection();
-               return -ENOMEM;
-       }
-       kfree(sel_buffer);
-       sel_buffer = bp;
-
-       obp = bp;
-       for (i = sel_start; i <= sel_end; i += 2) {
-               c = sel_pos(i);
-               if (use_unicode)
-                       bp += store_utf8(c, bp);
-               else
-                       *bp++ = c;
-               if (!isspace(c))
-                       obp = bp;
-               if (! ((i + 2) % vc->vc_size_row)) {
-                       /* strip trailing blanks from line and add newline,
-                          unless non-space at end of line. */
-                       if (obp != bp) {
-                               bp = obp;
-                               *bp++ = '\r';
-                       }
-                       obp = bp;
-               }
-       }
-       sel_buffer_lth = bp - sel_buffer;
-       return 0;
-}
-
-/* Insert the contents of the selection buffer into the
- * queue of the tty associated with the current console.
- * Invoked by ioctl().
- */
-int paste_selection(struct tty_struct *tty)
-{
-       struct vc_data *vc = tty->driver_data;
-       int     pasted = 0;
-       unsigned int count;
-       struct  tty_ldisc *ld;
-       DECLARE_WAITQUEUE(wait, current);
-
-       /* always called with BTM from vt_ioctl */
-       WARN_ON(!tty_locked());
-
-       acquire_console_sem();
-       poke_blanked_console();
-       release_console_sem();
-
-       ld = tty_ldisc_ref(tty);
-       if (!ld) {
-               tty_unlock();
-               ld = tty_ldisc_ref_wait(tty);
-               tty_lock();
-       }
-
-       add_wait_queue(&vc->paste_wait, &wait);
-       while (sel_buffer && sel_buffer_lth > pasted) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (test_bit(TTY_THROTTLED, &tty->flags)) {
-                       schedule();
-                       continue;
-               }
-               count = sel_buffer_lth - pasted;
-               count = min(count, tty->receive_room);
-               tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
-                                                               NULL, count);
-               pasted += count;
-       }
-       remove_wait_queue(&vc->paste_wait, &wait);
-       __set_current_state(TASK_RUNNING);
-
-       tty_ldisc_deref(ld);
-       return 0;
-}
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
deleted file mode 100644 (file)
index eaa5d3e..0000000
+++ /dev/null
@@ -1,811 +0,0 @@
-/*
- *     Linux Magic System Request Key Hacks
- *
- *     (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- *     based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
- *
- *     (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
- *     overhauled to use key registration
- *     based upon discusions in irc://irc.openprojects.net/#kernelnewbies
- *
- *     Copyright (c) 2010 Dmitry Torokhov
- *     Input handler conversion
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/kdev_t.h>
-#include <linux/major.h>
-#include <linux/reboot.h>
-#include <linux/sysrq.h>
-#include <linux/kbd_kern.h>
-#include <linux/proc_fs.h>
-#include <linux/nmi.h>
-#include <linux/quotaops.h>
-#include <linux/perf_event.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/suspend.h>
-#include <linux/writeback.h>
-#include <linux/buffer_head.h>         /* for fsync_bdev() */
-#include <linux/swap.h>
-#include <linux/spinlock.h>
-#include <linux/vt_kern.h>
-#include <linux/workqueue.h>
-#include <linux/hrtimer.h>
-#include <linux/oom.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-
-#include <asm/ptrace.h>
-#include <asm/irq_regs.h>
-
-/* Whether we react on sysrq keys or just ignore them */
-static int __read_mostly sysrq_enabled = 1;
-static bool __read_mostly sysrq_always_enabled;
-
-static bool sysrq_on(void)
-{
-       return sysrq_enabled || sysrq_always_enabled;
-}
-
-/*
- * A value of 1 means 'all', other nonzero values are an op mask:
- */
-static bool sysrq_on_mask(int mask)
-{
-       return sysrq_always_enabled ||
-              sysrq_enabled == 1 ||
-              (sysrq_enabled & mask);
-}
-
-static int __init sysrq_always_enabled_setup(char *str)
-{
-       sysrq_always_enabled = true;
-       pr_info("sysrq always enabled.\n");
-
-       return 1;
-}
-
-__setup("sysrq_always_enabled", sysrq_always_enabled_setup);
-
-
-static void sysrq_handle_loglevel(int key)
-{
-       int i;
-
-       i = key - '0';
-       console_loglevel = 7;
-       printk("Loglevel set to %d\n", i);
-       console_loglevel = i;
-}
-static struct sysrq_key_op sysrq_loglevel_op = {
-       .handler        = sysrq_handle_loglevel,
-       .help_msg       = "loglevel(0-9)",
-       .action_msg     = "Changing Loglevel",
-       .enable_mask    = SYSRQ_ENABLE_LOG,
-};
-
-#ifdef CONFIG_VT
-static void sysrq_handle_SAK(int key)
-{
-       struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
-       schedule_work(SAK_work);
-}
-static struct sysrq_key_op sysrq_SAK_op = {
-       .handler        = sysrq_handle_SAK,
-       .help_msg       = "saK",
-       .action_msg     = "SAK",
-       .enable_mask    = SYSRQ_ENABLE_KEYBOARD,
-};
-#else
-#define sysrq_SAK_op (*(struct sysrq_key_op *)NULL)
-#endif
-
-#ifdef CONFIG_VT
-static void sysrq_handle_unraw(int key)
-{
-       struct kbd_struct *kbd = &kbd_table[fg_console];
-
-       if (kbd)
-               kbd->kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
-}
-static struct sysrq_key_op sysrq_unraw_op = {
-       .handler        = sysrq_handle_unraw,
-       .help_msg       = "unRaw",
-       .action_msg     = "Keyboard mode set to system default",
-       .enable_mask    = SYSRQ_ENABLE_KEYBOARD,
-};
-#else
-#define sysrq_unraw_op (*(struct sysrq_key_op *)NULL)
-#endif /* CONFIG_VT */
-
-static void sysrq_handle_crash(int key)
-{
-       char *killer = NULL;
-
-       panic_on_oops = 1;      /* force panic */
-       wmb();
-       *killer = 1;
-}
-static struct sysrq_key_op sysrq_crash_op = {
-       .handler        = sysrq_handle_crash,
-       .help_msg       = "Crash",
-       .action_msg     = "Trigger a crash",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-
-static void sysrq_handle_reboot(int key)
-{
-       lockdep_off();
-       local_irq_enable();
-       emergency_restart();
-}
-static struct sysrq_key_op sysrq_reboot_op = {
-       .handler        = sysrq_handle_reboot,
-       .help_msg       = "reBoot",
-       .action_msg     = "Resetting",
-       .enable_mask    = SYSRQ_ENABLE_BOOT,
-};
-
-static void sysrq_handle_sync(int key)
-{
-       emergency_sync();
-}
-static struct sysrq_key_op sysrq_sync_op = {
-       .handler        = sysrq_handle_sync,
-       .help_msg       = "Sync",
-       .action_msg     = "Emergency Sync",
-       .enable_mask    = SYSRQ_ENABLE_SYNC,
-};
-
-static void sysrq_handle_show_timers(int key)
-{
-       sysrq_timer_list_show();
-}
-
-static struct sysrq_key_op sysrq_show_timers_op = {
-       .handler        = sysrq_handle_show_timers,
-       .help_msg       = "show-all-timers(Q)",
-       .action_msg     = "Show clockevent devices & pending hrtimers (no others)",
-};
-
-static void sysrq_handle_mountro(int key)
-{
-       emergency_remount();
-}
-static struct sysrq_key_op sysrq_mountro_op = {
-       .handler        = sysrq_handle_mountro,
-       .help_msg       = "Unmount",
-       .action_msg     = "Emergency Remount R/O",
-       .enable_mask    = SYSRQ_ENABLE_REMOUNT,
-};
-
-#ifdef CONFIG_LOCKDEP
-static void sysrq_handle_showlocks(int key)
-{
-       debug_show_all_locks();
-}
-
-static struct sysrq_key_op sysrq_showlocks_op = {
-       .handler        = sysrq_handle_showlocks,
-       .help_msg       = "show-all-locks(D)",
-       .action_msg     = "Show Locks Held",
-};
-#else
-#define sysrq_showlocks_op (*(struct sysrq_key_op *)NULL)
-#endif
-
-#ifdef CONFIG_SMP
-static DEFINE_SPINLOCK(show_lock);
-
-static void showacpu(void *dummy)
-{
-       unsigned long flags;
-
-       /* Idle CPUs have no interesting backtrace. */
-       if (idle_cpu(smp_processor_id()))
-               return;
-
-       spin_lock_irqsave(&show_lock, flags);
-       printk(KERN_INFO "CPU%d:\n", smp_processor_id());
-       show_stack(NULL, NULL);
-       spin_unlock_irqrestore(&show_lock, flags);
-}
-
-static void sysrq_showregs_othercpus(struct work_struct *dummy)
-{
-       smp_call_function(showacpu, NULL, 0);
-}
-
-static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus);
-
-static void sysrq_handle_showallcpus(int key)
-{
-       /*
-        * Fall back to the workqueue based printing if the
-        * backtrace printing did not succeed or the
-        * architecture has no support for it:
-        */
-       if (!trigger_all_cpu_backtrace()) {
-               struct pt_regs *regs = get_irq_regs();
-
-               if (regs) {
-                       printk(KERN_INFO "CPU%d:\n", smp_processor_id());
-                       show_regs(regs);
-               }
-               schedule_work(&sysrq_showallcpus);
-       }
-}
-
-static struct sysrq_key_op sysrq_showallcpus_op = {
-       .handler        = sysrq_handle_showallcpus,
-       .help_msg       = "show-backtrace-all-active-cpus(L)",
-       .action_msg     = "Show backtrace of all active CPUs",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-#endif
-
-static void sysrq_handle_showregs(int key)
-{
-       struct pt_regs *regs = get_irq_regs();
-       if (regs)
-               show_regs(regs);
-       perf_event_print_debug();
-}
-static struct sysrq_key_op sysrq_showregs_op = {
-       .handler        = sysrq_handle_showregs,
-       .help_msg       = "show-registers(P)",
-       .action_msg     = "Show Regs",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-
-static void sysrq_handle_showstate(int key)
-{
-       show_state();
-}
-static struct sysrq_key_op sysrq_showstate_op = {
-       .handler        = sysrq_handle_showstate,
-       .help_msg       = "show-task-states(T)",
-       .action_msg     = "Show State",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-
-static void sysrq_handle_showstate_blocked(int key)
-{
-       show_state_filter(TASK_UNINTERRUPTIBLE);
-}
-static struct sysrq_key_op sysrq_showstate_blocked_op = {
-       .handler        = sysrq_handle_showstate_blocked,
-       .help_msg       = "show-blocked-tasks(W)",
-       .action_msg     = "Show Blocked State",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-
-#ifdef CONFIG_TRACING
-#include <linux/ftrace.h>
-
-static void sysrq_ftrace_dump(int key)
-{
-       ftrace_dump(DUMP_ALL);
-}
-static struct sysrq_key_op sysrq_ftrace_dump_op = {
-       .handler        = sysrq_ftrace_dump,
-       .help_msg       = "dump-ftrace-buffer(Z)",
-       .action_msg     = "Dump ftrace buffer",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-#else
-#define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)NULL)
-#endif
-
-static void sysrq_handle_showmem(int key)
-{
-       show_mem();
-}
-static struct sysrq_key_op sysrq_showmem_op = {
-       .handler        = sysrq_handle_showmem,
-       .help_msg       = "show-memory-usage(M)",
-       .action_msg     = "Show Memory",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-
-/*
- * Signal sysrq helper function.  Sends a signal to all user processes.
- */
-static void send_sig_all(int sig)
-{
-       struct task_struct *p;
-
-       for_each_process(p) {
-               if (p->mm && !is_global_init(p))
-                       /* Not swapper, init nor kernel thread */
-                       force_sig(sig, p);
-       }
-}
-
-static void sysrq_handle_term(int key)
-{
-       send_sig_all(SIGTERM);
-       console_loglevel = 8;
-}
-static struct sysrq_key_op sysrq_term_op = {
-       .handler        = sysrq_handle_term,
-       .help_msg       = "terminate-all-tasks(E)",
-       .action_msg     = "Terminate All Tasks",
-       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
-};
-
-static void moom_callback(struct work_struct *ignored)
-{
-       out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0, NULL);
-}
-
-static DECLARE_WORK(moom_work, moom_callback);
-
-static void sysrq_handle_moom(int key)
-{
-       schedule_work(&moom_work);
-}
-static struct sysrq_key_op sysrq_moom_op = {
-       .handler        = sysrq_handle_moom,
-       .help_msg       = "memory-full-oom-kill(F)",
-       .action_msg     = "Manual OOM execution",
-       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
-};
-
-#ifdef CONFIG_BLOCK
-static void sysrq_handle_thaw(int key)
-{
-       emergency_thaw_all();
-}
-static struct sysrq_key_op sysrq_thaw_op = {
-       .handler        = sysrq_handle_thaw,
-       .help_msg       = "thaw-filesystems(J)",
-       .action_msg     = "Emergency Thaw of all frozen filesystems",
-       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
-};
-#endif
-
-static void sysrq_handle_kill(int key)
-{
-       send_sig_all(SIGKILL);
-       console_loglevel = 8;
-}
-static struct sysrq_key_op sysrq_kill_op = {
-       .handler        = sysrq_handle_kill,
-       .help_msg       = "kill-all-tasks(I)",
-       .action_msg     = "Kill All Tasks",
-       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
-};
-
-static void sysrq_handle_unrt(int key)
-{
-       normalize_rt_tasks();
-}
-static struct sysrq_key_op sysrq_unrt_op = {
-       .handler        = sysrq_handle_unrt,
-       .help_msg       = "nice-all-RT-tasks(N)",
-       .action_msg     = "Nice All RT Tasks",
-       .enable_mask    = SYSRQ_ENABLE_RTNICE,
-};
-
-/* Key Operations table and lock */
-static DEFINE_SPINLOCK(sysrq_key_table_lock);
-
-static struct sysrq_key_op *sysrq_key_table[36] = {
-       &sysrq_loglevel_op,             /* 0 */
-       &sysrq_loglevel_op,             /* 1 */
-       &sysrq_loglevel_op,             /* 2 */
-       &sysrq_loglevel_op,             /* 3 */
-       &sysrq_loglevel_op,             /* 4 */
-       &sysrq_loglevel_op,             /* 5 */
-       &sysrq_loglevel_op,             /* 6 */
-       &sysrq_loglevel_op,             /* 7 */
-       &sysrq_loglevel_op,             /* 8 */
-       &sysrq_loglevel_op,             /* 9 */
-
-       /*
-        * a: Don't use for system provided sysrqs, it is handled specially on
-        * sparc and will never arrive.
-        */
-       NULL,                           /* a */
-       &sysrq_reboot_op,               /* b */
-       &sysrq_crash_op,                /* c & ibm_emac driver debug */
-       &sysrq_showlocks_op,            /* d */
-       &sysrq_term_op,                 /* e */
-       &sysrq_moom_op,                 /* f */
-       /* g: May be registered for the kernel debugger */
-       NULL,                           /* g */
-       NULL,                           /* h - reserved for help */
-       &sysrq_kill_op,                 /* i */
-#ifdef CONFIG_BLOCK
-       &sysrq_thaw_op,                 /* j */
-#else
-       NULL,                           /* j */
-#endif
-       &sysrq_SAK_op,                  /* k */
-#ifdef CONFIG_SMP
-       &sysrq_showallcpus_op,          /* l */
-#else
-       NULL,                           /* l */
-#endif
-       &sysrq_showmem_op,              /* m */
-       &sysrq_unrt_op,                 /* n */
-       /* o: This will often be registered as 'Off' at init time */
-       NULL,                           /* o */
-       &sysrq_showregs_op,             /* p */
-       &sysrq_show_timers_op,          /* q */
-       &sysrq_unraw_op,                /* r */
-       &sysrq_sync_op,                 /* s */
-       &sysrq_showstate_op,            /* t */
-       &sysrq_mountro_op,              /* u */
-       /* v: May be registered for frame buffer console restore */
-       NULL,                           /* v */
-       &sysrq_showstate_blocked_op,    /* w */
-       /* x: May be registered on ppc/powerpc for xmon */
-       NULL,                           /* x */
-       /* y: May be registered on sparc64 for global register dump */
-       NULL,                           /* y */
-       &sysrq_ftrace_dump_op,          /* z */
-};
-
-/* key2index calculation, -1 on invalid index */
-static int sysrq_key_table_key2index(int key)
-{
-       int retval;
-
-       if ((key >= '0') && (key <= '9'))
-               retval = key - '0';
-       else if ((key >= 'a') && (key <= 'z'))
-               retval = key + 10 - 'a';
-       else
-               retval = -1;
-       return retval;
-}
-
-/*
- * get and put functions for the table, exposed to modules.
- */
-struct sysrq_key_op *__sysrq_get_key_op(int key)
-{
-        struct sysrq_key_op *op_p = NULL;
-        int i;
-
-       i = sysrq_key_table_key2index(key);
-       if (i != -1)
-               op_p = sysrq_key_table[i];
-
-        return op_p;
-}
-
-static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p)
-{
-        int i = sysrq_key_table_key2index(key);
-
-        if (i != -1)
-                sysrq_key_table[i] = op_p;
-}
-
-void __handle_sysrq(int key, bool check_mask)
-{
-       struct sysrq_key_op *op_p;
-       int orig_log_level;
-       int i;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sysrq_key_table_lock, flags);
-       /*
-        * Raise the apparent loglevel to maximum so that the sysrq header
-        * is shown to provide the user with positive feedback.  We do not
-        * simply emit this at KERN_EMERG as that would change message
-        * routing in the consumers of /proc/kmsg.
-        */
-       orig_log_level = console_loglevel;
-       console_loglevel = 7;
-       printk(KERN_INFO "SysRq : ");
-
-        op_p = __sysrq_get_key_op(key);
-        if (op_p) {
-               /*
-                * Should we check for enabled operations (/proc/sysrq-trigger
-                * should not) and is the invoked operation enabled?
-                */
-               if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
-                       printk("%s\n", op_p->action_msg);
-                       console_loglevel = orig_log_level;
-                       op_p->handler(key);
-               } else {
-                       printk("This sysrq operation is disabled.\n");
-               }
-       } else {
-               printk("HELP : ");
-               /* Only print the help msg once per handler */
-               for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) {
-                       if (sysrq_key_table[i]) {
-                               int j;
-
-                               for (j = 0; sysrq_key_table[i] !=
-                                               sysrq_key_table[j]; j++)
-                                       ;
-                               if (j != i)
-                                       continue;
-                               printk("%s ", sysrq_key_table[i]->help_msg);
-                       }
-               }
-               printk("\n");
-               console_loglevel = orig_log_level;
-       }
-       spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
-}
-
-void handle_sysrq(int key)
-{
-       if (sysrq_on())
-               __handle_sysrq(key, true);
-}
-EXPORT_SYMBOL(handle_sysrq);
-
-#ifdef CONFIG_INPUT
-
-/* Simple translation table for the SysRq keys */
-static const unsigned char sysrq_xlate[KEY_MAX + 1] =
-        "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
-        "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
-        "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
-        "bnm,./\000*\000 \000\201\202\203\204\205"      /* 0x30 - 0x3f */
-        "\206\207\210\211\212\000\000789-456+1"         /* 0x40 - 0x4f */
-        "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
-        "\r\000/";                                      /* 0x60 - 0x6f */
-
-static bool sysrq_down;
-static int sysrq_alt_use;
-static int sysrq_alt;
-static DEFINE_SPINLOCK(sysrq_event_lock);
-
-static bool sysrq_filter(struct input_handle *handle, unsigned int type,
-                        unsigned int code, int value)
-{
-       bool suppress;
-
-       /* We are called with interrupts disabled, just take the lock */
-       spin_lock(&sysrq_event_lock);
-
-       if (type != EV_KEY)
-               goto out;
-
-       switch (code) {
-
-       case KEY_LEFTALT:
-       case KEY_RIGHTALT:
-               if (value)
-                       sysrq_alt = code;
-               else {
-                       if (sysrq_down && code == sysrq_alt_use)
-                               sysrq_down = false;
-
-                       sysrq_alt = 0;
-               }
-               break;
-
-       case KEY_SYSRQ:
-               if (value == 1 && sysrq_alt) {
-                       sysrq_down = true;
-                       sysrq_alt_use = sysrq_alt;
-               }
-               break;
-
-       default:
-               if (sysrq_down && value && value != 2)
-                       __handle_sysrq(sysrq_xlate[code], true);
-               break;
-       }
-
-out:
-       suppress = sysrq_down;
-       spin_unlock(&sysrq_event_lock);
-
-       return suppress;
-}
-
-static int sysrq_connect(struct input_handler *handler,
-                        struct input_dev *dev,
-                        const struct input_device_id *id)
-{
-       struct input_handle *handle;
-       int error;
-
-       sysrq_down = false;
-       sysrq_alt = 0;
-
-       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
-       if (!handle)
-               return -ENOMEM;
-
-       handle->dev = dev;
-       handle->handler = handler;
-       handle->name = "sysrq";
-
-       error = input_register_handle(handle);
-       if (error) {
-               pr_err("Failed to register input sysrq handler, error %d\n",
-                       error);
-               goto err_free;
-       }
-
-       error = input_open_device(handle);
-       if (error) {
-               pr_err("Failed to open input device, error %d\n", error);
-               goto err_unregister;
-       }
-
-       return 0;
-
- err_unregister:
-       input_unregister_handle(handle);
- err_free:
-       kfree(handle);
-       return error;
-}
-
-static void sysrq_disconnect(struct input_handle *handle)
-{
-       input_close_device(handle);
-       input_unregister_handle(handle);
-       kfree(handle);
-}
-
-/*
- * We are matching on KEY_LEFTALT instead of KEY_SYSRQ because not all
- * keyboards have SysRq key predefined and so user may add it to keymap
- * later, but we expect all such keyboards to have left alt.
- */
-static const struct input_device_id sysrq_ids[] = {
-       {
-               .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
-                               INPUT_DEVICE_ID_MATCH_KEYBIT,
-               .evbit = { BIT_MASK(EV_KEY) },
-               .keybit = { BIT_MASK(KEY_LEFTALT) },
-       },
-       { },
-};
-
-static struct input_handler sysrq_handler = {
-       .filter         = sysrq_filter,
-       .connect        = sysrq_connect,
-       .disconnect     = sysrq_disconnect,
-       .name           = "sysrq",
-       .id_table       = sysrq_ids,
-};
-
-static bool sysrq_handler_registered;
-
-static inline void sysrq_register_handler(void)
-{
-       int error;
-
-       error = input_register_handler(&sysrq_handler);
-       if (error)
-               pr_err("Failed to register input handler, error %d", error);
-       else
-               sysrq_handler_registered = true;
-}
-
-static inline void sysrq_unregister_handler(void)
-{
-       if (sysrq_handler_registered) {
-               input_unregister_handler(&sysrq_handler);
-               sysrq_handler_registered = false;
-       }
-}
-
-#else
-
-static inline void sysrq_register_handler(void)
-{
-}
-
-static inline void sysrq_unregister_handler(void)
-{
-}
-
-#endif /* CONFIG_INPUT */
-
-int sysrq_toggle_support(int enable_mask)
-{
-       bool was_enabled = sysrq_on();
-
-       sysrq_enabled = enable_mask;
-
-       if (was_enabled != sysrq_on()) {
-               if (sysrq_on())
-                       sysrq_register_handler();
-               else
-                       sysrq_unregister_handler();
-       }
-
-       return 0;
-}
-
-static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
-                                struct sysrq_key_op *remove_op_p)
-{
-       int retval;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sysrq_key_table_lock, flags);
-       if (__sysrq_get_key_op(key) == remove_op_p) {
-               __sysrq_put_key_op(key, insert_op_p);
-               retval = 0;
-       } else {
-               retval = -1;
-       }
-       spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
-       return retval;
-}
-
-int register_sysrq_key(int key, struct sysrq_key_op *op_p)
-{
-       return __sysrq_swap_key_ops(key, op_p, NULL);
-}
-EXPORT_SYMBOL(register_sysrq_key);
-
-int unregister_sysrq_key(int key, struct sysrq_key_op *op_p)
-{
-       return __sysrq_swap_key_ops(key, NULL, op_p);
-}
-EXPORT_SYMBOL(unregister_sysrq_key);
-
-#ifdef CONFIG_PROC_FS
-/*
- * writing 'C' to /proc/sysrq-trigger is like sysrq-C
- */
-static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
-                                  size_t count, loff_t *ppos)
-{
-       if (count) {
-               char c;
-
-               if (get_user(c, buf))
-                       return -EFAULT;
-               __handle_sysrq(c, false);
-       }
-
-       return count;
-}
-
-static const struct file_operations proc_sysrq_trigger_operations = {
-       .write          = write_sysrq_trigger,
-       .llseek         = noop_llseek,
-};
-
-static void sysrq_init_procfs(void)
-{
-       if (!proc_create("sysrq-trigger", S_IWUSR, NULL,
-                        &proc_sysrq_trigger_operations))
-               pr_err("Failed to register proc interface\n");
-}
-
-#else
-
-static inline void sysrq_init_procfs(void)
-{
-}
-
-#endif /* CONFIG_PROC_FS */
-
-static int __init sysrq_init(void)
-{
-       sysrq_init_procfs();
-
-       if (sysrq_on())
-               sysrq_register_handler();
-
-       return 0;
-}
-module_init(sysrq_init);
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c
deleted file mode 100644 (file)
index f64582b..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Creating audit events from TTY input.
- *
- * Copyright (C) 2007 Red Hat, Inc.  All rights reserved.  This copyrighted
- * material is made available to anyone wishing to use, modify, copy, or
- * redistribute it subject to the terms and conditions of the GNU General
- * Public License v.2.
- *
- * Authors: Miloslav Trmac <mitr@redhat.com>
- */
-
-#include <linux/audit.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-
-struct tty_audit_buf {
-       atomic_t count;
-       struct mutex mutex;     /* Protects all data below */
-       int major, minor;       /* The TTY which the data is from */
-       unsigned icanon:1;
-       size_t valid;
-       unsigned char *data;    /* Allocated size N_TTY_BUF_SIZE */
-};
-
-static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
-                                                int icanon)
-{
-       struct tty_audit_buf *buf;
-
-       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
-       if (!buf)
-               goto err;
-       buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
-       if (!buf->data)
-               goto err_buf;
-       atomic_set(&buf->count, 1);
-       mutex_init(&buf->mutex);
-       buf->major = major;
-       buf->minor = minor;
-       buf->icanon = icanon;
-       buf->valid = 0;
-       return buf;
-
-err_buf:
-       kfree(buf);
-err:
-       return NULL;
-}
-
-static void tty_audit_buf_free(struct tty_audit_buf *buf)
-{
-       WARN_ON(buf->valid != 0);
-       kfree(buf->data);
-       kfree(buf);
-}
-
-static void tty_audit_buf_put(struct tty_audit_buf *buf)
-{
-       if (atomic_dec_and_test(&buf->count))
-               tty_audit_buf_free(buf);
-}
-
-static void tty_audit_log(const char *description, struct task_struct *tsk,
-                         uid_t loginuid, unsigned sessionid, int major,
-                         int minor, unsigned char *data, size_t size)
-{
-       struct audit_buffer *ab;
-
-       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
-       if (ab) {
-               char name[sizeof(tsk->comm)];
-               uid_t uid = task_uid(tsk);
-
-               audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u "
-                                "major=%d minor=%d comm=", description,
-                                tsk->pid, uid, loginuid, sessionid,
-                                major, minor);
-               get_task_comm(name, tsk);
-               audit_log_untrustedstring(ab, name);
-               audit_log_format(ab, " data=");
-               audit_log_n_hex(ab, data, size);
-               audit_log_end(ab);
-       }
-}
-
-/**
- *     tty_audit_buf_push      -       Push buffered data out
- *
- *     Generate an audit message from the contents of @buf, which is owned by
- *     @tsk with @loginuid.  @buf->mutex must be locked.
- */
-static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
-                              unsigned int sessionid,
-                              struct tty_audit_buf *buf)
-{
-       if (buf->valid == 0)
-               return;
-       if (audit_enabled == 0)
-               return;
-       tty_audit_log("tty", tsk, loginuid, sessionid, buf->major, buf->minor,
-                     buf->data, buf->valid);
-       buf->valid = 0;
-}
-
-/**
- *     tty_audit_buf_push_current      -       Push buffered data out
- *
- *     Generate an audit message from the contents of @buf, which is owned by
- *     the current task.  @buf->mutex must be locked.
- */
-static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
-{
-       uid_t auid = audit_get_loginuid(current);
-       unsigned int sessionid = audit_get_sessionid(current);
-       tty_audit_buf_push(current, auid, sessionid, buf);
-}
-
-/**
- *     tty_audit_exit  -       Handle a task exit
- *
- *     Make sure all buffered data is written out and deallocate the buffer.
- *     Only needs to be called if current->signal->tty_audit_buf != %NULL.
- */
-void tty_audit_exit(void)
-{
-       struct tty_audit_buf *buf;
-
-       spin_lock_irq(&current->sighand->siglock);
-       buf = current->signal->tty_audit_buf;
-       current->signal->tty_audit_buf = NULL;
-       spin_unlock_irq(&current->sighand->siglock);
-       if (!buf)
-               return;
-
-       mutex_lock(&buf->mutex);
-       tty_audit_buf_push_current(buf);
-       mutex_unlock(&buf->mutex);
-
-       tty_audit_buf_put(buf);
-}
-
-/**
- *     tty_audit_fork  -       Copy TTY audit state for a new task
- *
- *     Set up TTY audit state in @sig from current.  @sig needs no locking.
- */
-void tty_audit_fork(struct signal_struct *sig)
-{
-       spin_lock_irq(&current->sighand->siglock);
-       sig->audit_tty = current->signal->audit_tty;
-       spin_unlock_irq(&current->sighand->siglock);
-}
-
-/**
- *     tty_audit_tiocsti       -       Log TIOCSTI
- */
-void tty_audit_tiocsti(struct tty_struct *tty, char ch)
-{
-       struct tty_audit_buf *buf;
-       int major, minor, should_audit;
-
-       spin_lock_irq(&current->sighand->siglock);
-       should_audit = current->signal->audit_tty;
-       buf = current->signal->tty_audit_buf;
-       if (buf)
-               atomic_inc(&buf->count);
-       spin_unlock_irq(&current->sighand->siglock);
-
-       major = tty->driver->major;
-       minor = tty->driver->minor_start + tty->index;
-       if (buf) {
-               mutex_lock(&buf->mutex);
-               if (buf->major == major && buf->minor == minor)
-                       tty_audit_buf_push_current(buf);
-               mutex_unlock(&buf->mutex);
-               tty_audit_buf_put(buf);
-       }
-
-       if (should_audit && audit_enabled) {
-               uid_t auid;
-               unsigned int sessionid;
-
-               auid = audit_get_loginuid(current);
-               sessionid = audit_get_sessionid(current);
-               tty_audit_log("ioctl=TIOCSTI", current, auid, sessionid, major,
-                             minor, &ch, 1);
-       }
-}
-
-/**
- * tty_audit_push_task -       Flush task's pending audit data
- * @tsk:               task pointer
- * @loginuid:          sender login uid
- * @sessionid:         sender session id
- *
- * Called with a ref on @tsk held. Try to lock sighand and get a
- * reference to the tty audit buffer if available.
- * Flush the buffer or return an appropriate error code.
- */
-int tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
-{
-       struct tty_audit_buf *buf = ERR_PTR(-EPERM);
-       unsigned long flags;
-
-       if (!lock_task_sighand(tsk, &flags))
-               return -ESRCH;
-
-       if (tsk->signal->audit_tty) {
-               buf = tsk->signal->tty_audit_buf;
-               if (buf)
-                       atomic_inc(&buf->count);
-       }
-       unlock_task_sighand(tsk, &flags);
-
-       /*
-        * Return 0 when signal->audit_tty set
-        * but tsk->signal->tty_audit_buf == NULL.
-        */
-       if (!buf || IS_ERR(buf))
-               return PTR_ERR(buf);
-
-       mutex_lock(&buf->mutex);
-       tty_audit_buf_push(tsk, loginuid, sessionid, buf);
-       mutex_unlock(&buf->mutex);
-
-       tty_audit_buf_put(buf);
-       return 0;
-}
-
-/**
- *     tty_audit_buf_get       -       Get an audit buffer.
- *
- *     Get an audit buffer for @tty, allocate it if necessary.  Return %NULL
- *     if TTY auditing is disabled or out of memory.  Otherwise, return a new
- *     reference to the buffer.
- */
-static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
-{
-       struct tty_audit_buf *buf, *buf2;
-
-       buf = NULL;
-       buf2 = NULL;
-       spin_lock_irq(&current->sighand->siglock);
-       if (likely(!current->signal->audit_tty))
-               goto out;
-       buf = current->signal->tty_audit_buf;
-       if (buf) {
-               atomic_inc(&buf->count);
-               goto out;
-       }
-       spin_unlock_irq(&current->sighand->siglock);
-
-       buf2 = tty_audit_buf_alloc(tty->driver->major,
-                                  tty->driver->minor_start + tty->index,
-                                  tty->icanon);
-       if (buf2 == NULL) {
-               audit_log_lost("out of memory in TTY auditing");
-               return NULL;
-       }
-
-       spin_lock_irq(&current->sighand->siglock);
-       if (!current->signal->audit_tty)
-               goto out;
-       buf = current->signal->tty_audit_buf;
-       if (!buf) {
-               current->signal->tty_audit_buf = buf2;
-               buf = buf2;
-               buf2 = NULL;
-       }
-       atomic_inc(&buf->count);
-       /* Fall through */
- out:
-       spin_unlock_irq(&current->sighand->siglock);
-       if (buf2)
-               tty_audit_buf_free(buf2);
-       return buf;
-}
-
-/**
- *     tty_audit_add_data      -       Add data for TTY auditing.
- *
- *     Audit @data of @size from @tty, if necessary.
- */
-void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
-                       size_t size)
-{
-       struct tty_audit_buf *buf;
-       int major, minor;
-
-       if (unlikely(size == 0))
-               return;
-
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY
-           && tty->driver->subtype == PTY_TYPE_MASTER)
-               return;
-
-       buf = tty_audit_buf_get(tty);
-       if (!buf)
-               return;
-
-       mutex_lock(&buf->mutex);
-       major = tty->driver->major;
-       minor = tty->driver->minor_start + tty->index;
-       if (buf->major != major || buf->minor != minor
-           || buf->icanon != tty->icanon) {
-               tty_audit_buf_push_current(buf);
-               buf->major = major;
-               buf->minor = minor;
-               buf->icanon = tty->icanon;
-       }
-       do {
-               size_t run;
-
-               run = N_TTY_BUF_SIZE - buf->valid;
-               if (run > size)
-                       run = size;
-               memcpy(buf->data + buf->valid, data, run);
-               buf->valid += run;
-               data += run;
-               size -= run;
-               if (buf->valid == N_TTY_BUF_SIZE)
-                       tty_audit_buf_push_current(buf);
-       } while (size != 0);
-       mutex_unlock(&buf->mutex);
-       tty_audit_buf_put(buf);
-}
-
-/**
- *     tty_audit_push  -       Push buffered data out
- *
- *     Make sure no audit data is pending for @tty on the current process.
- */
-void tty_audit_push(struct tty_struct *tty)
-{
-       struct tty_audit_buf *buf;
-
-       spin_lock_irq(&current->sighand->siglock);
-       if (likely(!current->signal->audit_tty)) {
-               spin_unlock_irq(&current->sighand->siglock);
-               return;
-       }
-       buf = current->signal->tty_audit_buf;
-       if (buf)
-               atomic_inc(&buf->count);
-       spin_unlock_irq(&current->sighand->siglock);
-
-       if (buf) {
-               int major, minor;
-
-               major = tty->driver->major;
-               minor = tty->driver->minor_start + tty->index;
-               mutex_lock(&buf->mutex);
-               if (buf->major == major && buf->minor == minor)
-                       tty_audit_buf_push_current(buf);
-               mutex_unlock(&buf->mutex);
-               tty_audit_buf_put(buf);
-       }
-}
diff --git a/drivers/char/tty_buffer.c b/drivers/char/tty_buffer.c
deleted file mode 100644 (file)
index cc1e985..0000000
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Tty buffer allocation management
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-
-/**
- *     tty_buffer_free_all             -       free buffers used by a tty
- *     @tty: tty to free from
- *
- *     Remove all the buffers pending on a tty whether queued with data
- *     or in the free ring. Must be called when the tty is no longer in use
- *
- *     Locking: none
- */
-
-void tty_buffer_free_all(struct tty_struct *tty)
-{
-       struct tty_buffer *thead;
-       while ((thead = tty->buf.head) != NULL) {
-               tty->buf.head = thead->next;
-               kfree(thead);
-       }
-       while ((thead = tty->buf.free) != NULL) {
-               tty->buf.free = thead->next;
-               kfree(thead);
-       }
-       tty->buf.tail = NULL;
-       tty->buf.memory_used = 0;
-}
-
-/**
- *     tty_buffer_alloc        -       allocate a tty buffer
- *     @tty: tty device
- *     @size: desired size (characters)
- *
- *     Allocate a new tty buffer to hold the desired number of characters.
- *     Return NULL if out of memory or the allocation would exceed the
- *     per device queue
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
-{
-       struct tty_buffer *p;
-
-       if (tty->buf.memory_used + size > 65536)
-               return NULL;
-       p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
-       if (p == NULL)
-               return NULL;
-       p->used = 0;
-       p->size = size;
-       p->next = NULL;
-       p->commit = 0;
-       p->read = 0;
-       p->char_buf_ptr = (char *)(p->data);
-       p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
-       tty->buf.memory_used += size;
-       return p;
-}
-
-/**
- *     tty_buffer_free         -       free a tty buffer
- *     @tty: tty owning the buffer
- *     @b: the buffer to free
- *
- *     Free a tty buffer, or add it to the free list according to our
- *     internal strategy
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
-{
-       /* Dumb strategy for now - should keep some stats */
-       tty->buf.memory_used -= b->size;
-       WARN_ON(tty->buf.memory_used < 0);
-
-       if (b->size >= 512)
-               kfree(b);
-       else {
-               b->next = tty->buf.free;
-               tty->buf.free = b;
-       }
-}
-
-/**
- *     __tty_buffer_flush              -       flush full tty buffers
- *     @tty: tty to flush
- *
- *     flush all the buffers containing receive data. Caller must
- *     hold the buffer lock and must have ensured no parallel flush to
- *     ldisc is running.
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static void __tty_buffer_flush(struct tty_struct *tty)
-{
-       struct tty_buffer *thead;
-
-       while ((thead = tty->buf.head) != NULL) {
-               tty->buf.head = thead->next;
-               tty_buffer_free(tty, thead);
-       }
-       tty->buf.tail = NULL;
-}
-
-/**
- *     tty_buffer_flush                -       flush full tty buffers
- *     @tty: tty to flush
- *
- *     flush all the buffers containing receive data. If the buffer is
- *     being processed by flush_to_ldisc then we defer the processing
- *     to that function
- *
- *     Locking: none
- */
-
-void tty_buffer_flush(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->buf.lock, flags);
-
-       /* If the data is being pushed to the tty layer then we can't
-          process it here. Instead set a flag and the flush_to_ldisc
-          path will process the flush request before it exits */
-       if (test_bit(TTY_FLUSHING, &tty->flags)) {
-               set_bit(TTY_FLUSHPENDING, &tty->flags);
-               spin_unlock_irqrestore(&tty->buf.lock, flags);
-               wait_event(tty->read_wait,
-                               test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
-               return;
-       } else
-               __tty_buffer_flush(tty);
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-}
-
-/**
- *     tty_buffer_find         -       find a free tty buffer
- *     @tty: tty owning the buffer
- *     @size: characters wanted
- *
- *     Locate an existing suitable tty buffer or if we are lacking one then
- *     allocate a new one. We round our buffers off in 256 character chunks
- *     to get better allocation behaviour.
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
-{
-       struct tty_buffer **tbh = &tty->buf.free;
-       while ((*tbh) != NULL) {
-               struct tty_buffer *t = *tbh;
-               if (t->size >= size) {
-                       *tbh = t->next;
-                       t->next = NULL;
-                       t->used = 0;
-                       t->commit = 0;
-                       t->read = 0;
-                       tty->buf.memory_used += t->size;
-                       return t;
-               }
-               tbh = &((*tbh)->next);
-       }
-       /* Round the buffer size out */
-       size = (size + 0xFF) & ~0xFF;
-       return tty_buffer_alloc(tty, size);
-       /* Should possibly check if this fails for the largest buffer we
-          have queued and recycle that ? */
-}
-
-/**
- *     tty_buffer_request_room         -       grow tty buffer if needed
- *     @tty: tty structure
- *     @size: size desired
- *
- *     Make at least size bytes of linear space available for the tty
- *     buffer. If we fail return the size we managed to find.
- *
- *     Locking: Takes tty->buf.lock
- */
-int tty_buffer_request_room(struct tty_struct *tty, size_t size)
-{
-       struct tty_buffer *b, *n;
-       int left;
-       unsigned long flags;
-
-       spin_lock_irqsave(&tty->buf.lock, flags);
-
-       /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
-          remove this conditional if its worth it. This would be invisible
-          to the callers */
-       if ((b = tty->buf.tail) != NULL)
-               left = b->size - b->used;
-       else
-               left = 0;
-
-       if (left < size) {
-               /* This is the slow path - looking for new buffers to use */
-               if ((n = tty_buffer_find(tty, size)) != NULL) {
-                       if (b != NULL) {
-                               b->next = n;
-                               b->commit = b->used;
-                       } else
-                               tty->buf.head = n;
-                       tty->buf.tail = n;
-               } else
-                       size = left;
-       }
-
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-       return size;
-}
-EXPORT_SYMBOL_GPL(tty_buffer_request_room);
-
-/**
- *     tty_insert_flip_string_fixed_flag - Add characters to the tty buffer
- *     @tty: tty structure
- *     @chars: characters
- *     @flag: flag value for each character
- *     @size: size
- *
- *     Queue a series of bytes to the tty buffering. All the characters
- *     passed are marked with the supplied flag. Returns the number added.
- *
- *     Locking: Called functions may take tty->buf.lock
- */
-
-int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
-               const unsigned char *chars, char flag, size_t size)
-{
-       int copied = 0;
-       do {
-               int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-               int space = tty_buffer_request_room(tty, goal);
-               struct tty_buffer *tb = tty->buf.tail;
-               /* If there is no space then tb may be NULL */
-               if (unlikely(space == 0))
-                       break;
-               memcpy(tb->char_buf_ptr + tb->used, chars, space);
-               memset(tb->flag_buf_ptr + tb->used, flag, space);
-               tb->used += space;
-               copied += space;
-               chars += space;
-               /* There is a small chance that we need to split the data over
-                  several buffers. If this is the case we must loop */
-       } while (unlikely(size > copied));
-       return copied;
-}
-EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag);
-
-/**
- *     tty_insert_flip_string_flags    -       Add characters to the tty buffer
- *     @tty: tty structure
- *     @chars: characters
- *     @flags: flag bytes
- *     @size: size
- *
- *     Queue a series of bytes to the tty buffering. For each character
- *     the flags array indicates the status of the character. Returns the
- *     number added.
- *
- *     Locking: Called functions may take tty->buf.lock
- */
-
-int tty_insert_flip_string_flags(struct tty_struct *tty,
-               const unsigned char *chars, const char *flags, size_t size)
-{
-       int copied = 0;
-       do {
-               int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-               int space = tty_buffer_request_room(tty, goal);
-               struct tty_buffer *tb = tty->buf.tail;
-               /* If there is no space then tb may be NULL */
-               if (unlikely(space == 0))
-                       break;
-               memcpy(tb->char_buf_ptr + tb->used, chars, space);
-               memcpy(tb->flag_buf_ptr + tb->used, flags, space);
-               tb->used += space;
-               copied += space;
-               chars += space;
-               flags += space;
-               /* There is a small chance that we need to split the data over
-                  several buffers. If this is the case we must loop */
-       } while (unlikely(size > copied));
-       return copied;
-}
-EXPORT_SYMBOL(tty_insert_flip_string_flags);
-
-/**
- *     tty_schedule_flip       -       push characters to ldisc
- *     @tty: tty to push from
- *
- *     Takes any pending buffers and transfers their ownership to the
- *     ldisc side of the queue. It then schedules those characters for
- *     processing by the line discipline.
- *
- *     Locking: Takes tty->buf.lock
- */
-
-void tty_schedule_flip(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->buf.lock, flags);
-       if (tty->buf.tail != NULL)
-               tty->buf.tail->commit = tty->buf.tail->used;
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-       schedule_delayed_work(&tty->buf.work, 1);
-}
-EXPORT_SYMBOL(tty_schedule_flip);
-
-/**
- *     tty_prepare_flip_string         -       make room for characters
- *     @tty: tty
- *     @chars: return pointer for character write area
- *     @size: desired size
- *
- *     Prepare a block of space in the buffer for data. Returns the length
- *     available and buffer pointer to the space which is now allocated and
- *     accounted for as ready for normal characters. This is used for drivers
- *     that need their own block copy routines into the buffer. There is no
- *     guarantee the buffer is a DMA target!
- *
- *     Locking: May call functions taking tty->buf.lock
- */
-
-int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
-                                                               size_t size)
-{
-       int space = tty_buffer_request_room(tty, size);
-       if (likely(space)) {
-               struct tty_buffer *tb = tty->buf.tail;
-               *chars = tb->char_buf_ptr + tb->used;
-               memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
-               tb->used += space;
-       }
-       return space;
-}
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
-
-/**
- *     tty_prepare_flip_string_flags   -       make room for characters
- *     @tty: tty
- *     @chars: return pointer for character write area
- *     @flags: return pointer for status flag write area
- *     @size: desired size
- *
- *     Prepare a block of space in the buffer for data. Returns the length
- *     available and buffer pointer to the space which is now allocated and
- *     accounted for as ready for characters. This is used for drivers
- *     that need their own block copy routines into the buffer. There is no
- *     guarantee the buffer is a DMA target!
- *
- *     Locking: May call functions taking tty->buf.lock
- */
-
-int tty_prepare_flip_string_flags(struct tty_struct *tty,
-                       unsigned char **chars, char **flags, size_t size)
-{
-       int space = tty_buffer_request_room(tty, size);
-       if (likely(space)) {
-               struct tty_buffer *tb = tty->buf.tail;
-               *chars = tb->char_buf_ptr + tb->used;
-               *flags = tb->flag_buf_ptr + tb->used;
-               tb->used += space;
-       }
-       return space;
-}
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
-
-
-
-/**
- *     flush_to_ldisc
- *     @work: tty structure passed from work queue.
- *
- *     This routine is called out of the software interrupt to flush data
- *     from the buffer chain to the line discipline.
- *
- *     Locking: holds tty->buf.lock to guard buffer list. Drops the lock
- *     while invoking the line discipline receive_buf method. The
- *     receive_buf method is single threaded for each tty instance.
- */
-
-static void flush_to_ldisc(struct work_struct *work)
-{
-       struct tty_struct *tty =
-               container_of(work, struct tty_struct, buf.work.work);
-       unsigned long   flags;
-       struct tty_ldisc *disc;
-
-       disc = tty_ldisc_ref(tty);
-       if (disc == NULL)       /*  !TTY_LDISC */
-               return;
-
-       spin_lock_irqsave(&tty->buf.lock, flags);
-
-       if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) {
-               struct tty_buffer *head;
-               while ((head = tty->buf.head) != NULL) {
-                       int count;
-                       char *char_buf;
-                       unsigned char *flag_buf;
-
-                       count = head->commit - head->read;
-                       if (!count) {
-                               if (head->next == NULL)
-                                       break;
-                               tty->buf.head = head->next;
-                               tty_buffer_free(tty, head);
-                               continue;
-                       }
-                       /* Ldisc or user is trying to flush the buffers
-                          we are feeding to the ldisc, stop feeding the
-                          line discipline as we want to empty the queue */
-                       if (test_bit(TTY_FLUSHPENDING, &tty->flags))
-                               break;
-                       if (!tty->receive_room) {
-                               schedule_delayed_work(&tty->buf.work, 1);
-                               break;
-                       }
-                       if (count > tty->receive_room)
-                               count = tty->receive_room;
-                       char_buf = head->char_buf_ptr + head->read;
-                       flag_buf = head->flag_buf_ptr + head->read;
-                       head->read += count;
-                       spin_unlock_irqrestore(&tty->buf.lock, flags);
-                       disc->ops->receive_buf(tty, char_buf,
-                                                       flag_buf, count);
-                       spin_lock_irqsave(&tty->buf.lock, flags);
-               }
-               clear_bit(TTY_FLUSHING, &tty->flags);
-       }
-
-       /* We may have a deferred request to flush the input buffer,
-          if so pull the chain under the lock and empty the queue */
-       if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
-               __tty_buffer_flush(tty);
-               clear_bit(TTY_FLUSHPENDING, &tty->flags);
-               wake_up(&tty->read_wait);
-       }
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-
-       tty_ldisc_deref(disc);
-}
-
-/**
- *     tty_flush_to_ldisc
- *     @tty: tty to push
- *
- *     Push the terminal flip buffers to the line discipline.
- *
- *     Must not be called from IRQ context.
- */
-void tty_flush_to_ldisc(struct tty_struct *tty)
-{
-       flush_delayed_work(&tty->buf.work);
-}
-
-/**
- *     tty_flip_buffer_push    -       terminal
- *     @tty: tty to push
- *
- *     Queue a push of the terminal flip buffers to the line discipline. This
- *     function must not be called from IRQ context if tty->low_latency is set.
- *
- *     In the event of the queue being busy for flipping the work will be
- *     held off and retried later.
- *
- *     Locking: tty buffer lock. Driver locks in low latency mode.
- */
-
-void tty_flip_buffer_push(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->buf.lock, flags);
-       if (tty->buf.tail != NULL)
-               tty->buf.tail->commit = tty->buf.tail->used;
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-
-       if (tty->low_latency)
-               flush_to_ldisc(&tty->buf.work.work);
-       else
-               schedule_delayed_work(&tty->buf.work, 1);
-}
-EXPORT_SYMBOL(tty_flip_buffer_push);
-
-/**
- *     tty_buffer_init         -       prepare a tty buffer structure
- *     @tty: tty to initialise
- *
- *     Set up the initial state of the buffer management for a tty device.
- *     Must be called before the other tty buffer functions are used.
- *
- *     Locking: none
- */
-
-void tty_buffer_init(struct tty_struct *tty)
-{
-       spin_lock_init(&tty->buf.lock);
-       tty->buf.head = NULL;
-       tty->buf.tail = NULL;
-       tty->buf.free = NULL;
-       tty->buf.memory_used = 0;
-       INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
-}
-
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
deleted file mode 100644 (file)
index c05c5af..0000000
+++ /dev/null
@@ -1,3263 +0,0 @@
-/*
- *  linux/drivers/char/tty_io.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-/*
- * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
- * or rs-channels. It also implements echoing, cooked mode etc.
- *
- * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
- *
- * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
- * tty_struct and tty_queue structures.  Previously there was an array
- * of 256 tty_struct's which was statically allocated, and the
- * tty_queue structures were allocated at boot time.  Both are now
- * dynamically allocated only when the tty is open.
- *
- * Also restructured routines so that there is more of a separation
- * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
- * the low-level tty routines (serial.c, pty.c, console.c).  This
- * makes for cleaner and more compact code.  -TYT, 9/17/92
- *
- * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
- * which can be dynamically activated and de-activated by the line
- * discipline handling modules (like SLIP).
- *
- * NOTE: pay no attention to the line discipline code (yet); its
- * interface is still subject to change in this version...
- * -- TYT, 1/31/92
- *
- * Added functionality to the OPOST tty handling.  No delays, but all
- * other bits should be there.
- *     -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
- *
- * Rewrote canonical mode and added more termios flags.
- *     -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
- *
- * Reorganized FASYNC support so mouse code can share it.
- *     -- ctm@ardi.com, 9Sep95
- *
- * New TIOCLINUX variants added.
- *     -- mj@k332.feld.cvut.cz, 19-Nov-95
- *
- * Restrict vt switching via ioctl()
- *      -- grif@cs.ucr.edu, 5-Dec-95
- *
- * Move console and virtual terminal code to more appropriate files,
- * implement CONFIG_VT and generalize console device interface.
- *     -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
- *
- * Rewrote tty_init_dev and tty_release_dev to eliminate races.
- *     -- Bill Hawes <whawes@star.net>, June 97
- *
- * Added devfs support.
- *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 13-Jan-1998
- *
- * Added support for a Unix98-style ptmx device.
- *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
- *
- * Reduced memory usage for older ARM systems
- *      -- Russell King <rmk@arm.linux.org.uk>
- *
- * Move do_SAK() into process context.  Less stack use in devfs functions.
- * alloc_tty_struct() always uses kmalloc()
- *                      -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01
- */
-
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/devpts_fs.h>
-#include <linux/file.h>
-#include <linux/fdtable.h>
-#include <linux/console.h>
-#include <linux/timer.h>
-#include <linux/ctype.h>
-#include <linux/kd.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/smp_lock.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/seq_file.h>
-#include <linux/serial.h>
-
-#include <linux/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-
-#include <linux/kmod.h>
-#include <linux/nsproxy.h>
-
-#undef TTY_DEBUG_HANGUP
-
-#define TTY_PARANOIA_CHECK 1
-#define CHECK_TTY_COUNT 1
-
-struct ktermios tty_std_termios = {    /* for the benefit of tty drivers  */
-       .c_iflag = ICRNL | IXON,
-       .c_oflag = OPOST | ONLCR,
-       .c_cflag = B38400 | CS8 | CREAD | HUPCL,
-       .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
-                  ECHOCTL | ECHOKE | IEXTEN,
-       .c_cc = INIT_C_CC,
-       .c_ispeed = 38400,
-       .c_ospeed = 38400
-};
-
-EXPORT_SYMBOL(tty_std_termios);
-
-/* This list gets poked at by procfs and various bits of boot up code. This
-   could do with some rationalisation such as pulling the tty proc function
-   into this file */
-
-LIST_HEAD(tty_drivers);                        /* linked list of tty drivers */
-
-/* Mutex to protect creating and releasing a tty. This is shared with
-   vt.c for deeply disgusting hack reasons */
-DEFINE_MUTEX(tty_mutex);
-EXPORT_SYMBOL(tty_mutex);
-
-/* Spinlock to protect the tty->tty_files list */
-DEFINE_SPINLOCK(tty_files_lock);
-
-static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
-static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
-ssize_t redirected_tty_write(struct file *, const char __user *,
-                                                       size_t, loff_t *);
-static unsigned int tty_poll(struct file *, poll_table *);
-static int tty_open(struct inode *, struct file *);
-long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-#ifdef CONFIG_COMPAT
-static long tty_compat_ioctl(struct file *file, unsigned int cmd,
-                               unsigned long arg);
-#else
-#define tty_compat_ioctl NULL
-#endif
-static int __tty_fasync(int fd, struct file *filp, int on);
-static int tty_fasync(int fd, struct file *filp, int on);
-static void release_tty(struct tty_struct *tty, int idx);
-static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
-static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
-
-/**
- *     alloc_tty_struct        -       allocate a tty object
- *
- *     Return a new empty tty structure. The data fields have not
- *     been initialized in any way but has been zeroed
- *
- *     Locking: none
- */
-
-struct tty_struct *alloc_tty_struct(void)
-{
-       return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
-}
-
-/**
- *     free_tty_struct         -       free a disused tty
- *     @tty: tty struct to free
- *
- *     Free the write buffers, tty queue and tty memory itself.
- *
- *     Locking: none. Must be called after tty is definitely unused
- */
-
-void free_tty_struct(struct tty_struct *tty)
-{
-       if (tty->dev)
-               put_device(tty->dev);
-       kfree(tty->write_buf);
-       tty_buffer_free_all(tty);
-       kfree(tty);
-}
-
-static inline struct tty_struct *file_tty(struct file *file)
-{
-       return ((struct tty_file_private *)file->private_data)->tty;
-}
-
-/* Associate a new file with the tty structure */
-int tty_add_file(struct tty_struct *tty, struct file *file)
-{
-       struct tty_file_private *priv;
-
-       priv = kmalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->tty = tty;
-       priv->file = file;
-       file->private_data = priv;
-
-       spin_lock(&tty_files_lock);
-       list_add(&priv->list, &tty->tty_files);
-       spin_unlock(&tty_files_lock);
-
-       return 0;
-}
-
-/* Delete file from its tty */
-void tty_del_file(struct file *file)
-{
-       struct tty_file_private *priv = file->private_data;
-
-       spin_lock(&tty_files_lock);
-       list_del(&priv->list);
-       spin_unlock(&tty_files_lock);
-       file->private_data = NULL;
-       kfree(priv);
-}
-
-
-#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)
-
-/**
- *     tty_name        -       return tty naming
- *     @tty: tty structure
- *     @buf: buffer for output
- *
- *     Convert a tty structure into a name. The name reflects the kernel
- *     naming policy and if udev is in use may not reflect user space
- *
- *     Locking: none
- */
-
-char *tty_name(struct tty_struct *tty, char *buf)
-{
-       if (!tty) /* Hmm.  NULL pointer.  That's fun. */
-               strcpy(buf, "NULL tty");
-       else
-               strcpy(buf, tty->name);
-       return buf;
-}
-
-EXPORT_SYMBOL(tty_name);
-
-int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
-                             const char *routine)
-{
-#ifdef TTY_PARANOIA_CHECK
-       if (!tty) {
-               printk(KERN_WARNING
-                       "null TTY for (%d:%d) in %s\n",
-                       imajor(inode), iminor(inode), routine);
-               return 1;
-       }
-       if (tty->magic != TTY_MAGIC) {
-               printk(KERN_WARNING
-                       "bad magic number for tty struct (%d:%d) in %s\n",
-                       imajor(inode), iminor(inode), routine);
-               return 1;
-       }
-#endif
-       return 0;
-}
-
-static int check_tty_count(struct tty_struct *tty, const char *routine)
-{
-#ifdef CHECK_TTY_COUNT
-       struct list_head *p;
-       int count = 0;
-
-       spin_lock(&tty_files_lock);
-       list_for_each(p, &tty->tty_files) {
-               count++;
-       }
-       spin_unlock(&tty_files_lock);
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->driver->subtype == PTY_TYPE_SLAVE &&
-           tty->link && tty->link->count)
-               count++;
-       if (tty->count != count) {
-               printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "
-                                   "!= #fd's(%d) in %s\n",
-                      tty->name, tty->count, count, routine);
-               return count;
-       }
-#endif
-       return 0;
-}
-
-/**
- *     get_tty_driver          -       find device of a tty
- *     @dev_t: device identifier
- *     @index: returns the index of the tty
- *
- *     This routine returns a tty driver structure, given a device number
- *     and also passes back the index number.
- *
- *     Locking: caller must hold tty_mutex
- */
-
-static struct tty_driver *get_tty_driver(dev_t device, int *index)
-{
-       struct tty_driver *p;
-
-       list_for_each_entry(p, &tty_drivers, tty_drivers) {
-               dev_t base = MKDEV(p->major, p->minor_start);
-               if (device < base || device >= base + p->num)
-                       continue;
-               *index = device - base;
-               return tty_driver_kref_get(p);
-       }
-       return NULL;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-
-/**
- *     tty_find_polling_driver -       find device of a polled tty
- *     @name: name string to match
- *     @line: pointer to resulting tty line nr
- *
- *     This routine returns a tty driver structure, given a name
- *     and the condition that the tty driver is capable of polled
- *     operation.
- */
-struct tty_driver *tty_find_polling_driver(char *name, int *line)
-{
-       struct tty_driver *p, *res = NULL;
-       int tty_line = 0;
-       int len;
-       char *str, *stp;
-
-       for (str = name; *str; str++)
-               if ((*str >= '0' && *str <= '9') || *str == ',')
-                       break;
-       if (!*str)
-               return NULL;
-
-       len = str - name;
-       tty_line = simple_strtoul(str, &str, 10);
-
-       mutex_lock(&tty_mutex);
-       /* Search through the tty devices to look for a match */
-       list_for_each_entry(p, &tty_drivers, tty_drivers) {
-               if (strncmp(name, p->name, len) != 0)
-                       continue;
-               stp = str;
-               if (*stp == ',')
-                       stp++;
-               if (*stp == '\0')
-                       stp = NULL;
-
-               if (tty_line >= 0 && tty_line < p->num && p->ops &&
-                   p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {
-                       res = tty_driver_kref_get(p);
-                       *line = tty_line;
-                       break;
-               }
-       }
-       mutex_unlock(&tty_mutex);
-
-       return res;
-}
-EXPORT_SYMBOL_GPL(tty_find_polling_driver);
-#endif
-
-/**
- *     tty_check_change        -       check for POSIX terminal changes
- *     @tty: tty to check
- *
- *     If we try to write to, or set the state of, a terminal and we're
- *     not in the foreground, send a SIGTTOU.  If the signal is blocked or
- *     ignored, go ahead and perform the operation.  (POSIX 7.2)
- *
- *     Locking: ctrl_lock
- */
-
-int tty_check_change(struct tty_struct *tty)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       if (current->signal->tty != tty)
-               return 0;
-
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-
-       if (!tty->pgrp) {
-               printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
-               goto out_unlock;
-       }
-       if (task_pgrp(current) == tty->pgrp)
-               goto out_unlock;
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-       if (is_ignored(SIGTTOU))
-               goto out;
-       if (is_current_pgrp_orphaned()) {
-               ret = -EIO;
-               goto out;
-       }
-       kill_pgrp(task_pgrp(current), SIGTTOU, 1);
-       set_thread_flag(TIF_SIGPENDING);
-       ret = -ERESTARTSYS;
-out:
-       return ret;
-out_unlock:
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-       return ret;
-}
-
-EXPORT_SYMBOL(tty_check_change);
-
-static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
-                               size_t count, loff_t *ppos)
-{
-       return 0;
-}
-
-static ssize_t hung_up_tty_write(struct file *file, const char __user *buf,
-                                size_t count, loff_t *ppos)
-{
-       return -EIO;
-}
-
-/* No kernel lock held - none needed ;) */
-static unsigned int hung_up_tty_poll(struct file *filp, poll_table *wait)
-{
-       return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
-}
-
-static long hung_up_tty_ioctl(struct file *file, unsigned int cmd,
-               unsigned long arg)
-{
-       return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
-}
-
-static long hung_up_tty_compat_ioctl(struct file *file,
-                                    unsigned int cmd, unsigned long arg)
-{
-       return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
-}
-
-static const struct file_operations tty_fops = {
-       .llseek         = no_llseek,
-       .read           = tty_read,
-       .write          = tty_write,
-       .poll           = tty_poll,
-       .unlocked_ioctl = tty_ioctl,
-       .compat_ioctl   = tty_compat_ioctl,
-       .open           = tty_open,
-       .release        = tty_release,
-       .fasync         = tty_fasync,
-};
-
-static const struct file_operations console_fops = {
-       .llseek         = no_llseek,
-       .read           = tty_read,
-       .write          = redirected_tty_write,
-       .poll           = tty_poll,
-       .unlocked_ioctl = tty_ioctl,
-       .compat_ioctl   = tty_compat_ioctl,
-       .open           = tty_open,
-       .release        = tty_release,
-       .fasync         = tty_fasync,
-};
-
-static const struct file_operations hung_up_tty_fops = {
-       .llseek         = no_llseek,
-       .read           = hung_up_tty_read,
-       .write          = hung_up_tty_write,
-       .poll           = hung_up_tty_poll,
-       .unlocked_ioctl = hung_up_tty_ioctl,
-       .compat_ioctl   = hung_up_tty_compat_ioctl,
-       .release        = tty_release,
-};
-
-static DEFINE_SPINLOCK(redirect_lock);
-static struct file *redirect;
-
-/**
- *     tty_wakeup      -       request more data
- *     @tty: terminal
- *
- *     Internal and external helper for wakeups of tty. This function
- *     informs the line discipline if present that the driver is ready
- *     to receive more output data.
- */
-
-void tty_wakeup(struct tty_struct *tty)
-{
-       struct tty_ldisc *ld;
-
-       if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) {
-               ld = tty_ldisc_ref(tty);
-               if (ld) {
-                       if (ld->ops->write_wakeup)
-                               ld->ops->write_wakeup(tty);
-                       tty_ldisc_deref(ld);
-               }
-       }
-       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
-}
-
-EXPORT_SYMBOL_GPL(tty_wakeup);
-
-/**
- *     __tty_hangup            -       actual handler for hangup events
- *     @work: tty device
- *
- *     This can be called by the "eventd" kernel thread.  That is process
- *     synchronous but doesn't hold any locks, so we need to make sure we
- *     have the appropriate locks for what we're doing.
- *
- *     The hangup event clears any pending redirections onto the hung up
- *     device. It ensures future writes will error and it does the needed
- *     line discipline hangup and signal delivery. The tty object itself
- *     remains intact.
- *
- *     Locking:
- *             BTM
- *               redirect lock for undoing redirection
- *               file list lock for manipulating list of ttys
- *               tty_ldisc_lock from called functions
- *               termios_mutex resetting termios data
- *               tasklist_lock to walk task list for hangup event
- *                 ->siglock to protect ->signal/->sighand
- */
-void __tty_hangup(struct tty_struct *tty)
-{
-       struct file *cons_filp = NULL;
-       struct file *filp, *f = NULL;
-       struct task_struct *p;
-       struct tty_file_private *priv;
-       int    closecount = 0, n;
-       unsigned long flags;
-       int refs = 0;
-
-       if (!tty)
-               return;
-
-
-       spin_lock(&redirect_lock);
-       if (redirect && file_tty(redirect) == tty) {
-               f = redirect;
-               redirect = NULL;
-       }
-       spin_unlock(&redirect_lock);
-
-       tty_lock();
-
-       /* inuse_filps is protected by the single tty lock,
-          this really needs to change if we want to flush the
-          workqueue with the lock held */
-       check_tty_count(tty, "tty_hangup");
-
-       spin_lock(&tty_files_lock);
-       /* This breaks for file handles being sent over AF_UNIX sockets ? */
-       list_for_each_entry(priv, &tty->tty_files, list) {
-               filp = priv->file;
-               if (filp->f_op->write == redirected_tty_write)
-                       cons_filp = filp;
-               if (filp->f_op->write != tty_write)
-                       continue;
-               closecount++;
-               __tty_fasync(-1, filp, 0);      /* can't block */
-               filp->f_op = &hung_up_tty_fops;
-       }
-       spin_unlock(&tty_files_lock);
-
-       tty_ldisc_hangup(tty);
-
-       read_lock(&tasklist_lock);
-       if (tty->session) {
-               do_each_pid_task(tty->session, PIDTYPE_SID, p) {
-                       spin_lock_irq(&p->sighand->siglock);
-                       if (p->signal->tty == tty) {
-                               p->signal->tty = NULL;
-                               /* We defer the dereferences outside fo
-                                  the tasklist lock */
-                               refs++;
-                       }
-                       if (!p->signal->leader) {
-                               spin_unlock_irq(&p->sighand->siglock);
-                               continue;
-                       }
-                       __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
-                       __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
-                       put_pid(p->signal->tty_old_pgrp);  /* A noop */
-                       spin_lock_irqsave(&tty->ctrl_lock, flags);
-                       if (tty->pgrp)
-                               p->signal->tty_old_pgrp = get_pid(tty->pgrp);
-                       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-                       spin_unlock_irq(&p->sighand->siglock);
-               } while_each_pid_task(tty->session, PIDTYPE_SID, p);
-       }
-       read_unlock(&tasklist_lock);
-
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       clear_bit(TTY_THROTTLED, &tty->flags);
-       clear_bit(TTY_PUSH, &tty->flags);
-       clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-       put_pid(tty->session);
-       put_pid(tty->pgrp);
-       tty->session = NULL;
-       tty->pgrp = NULL;
-       tty->ctrl_status = 0;
-       set_bit(TTY_HUPPED, &tty->flags);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-       /* Account for the p->signal references we killed */
-       while (refs--)
-               tty_kref_put(tty);
-
-       /*
-        * If one of the devices matches a console pointer, we
-        * cannot just call hangup() because that will cause
-        * tty->count and state->count to go out of sync.
-        * So we just call close() the right number of times.
-        */
-       if (cons_filp) {
-               if (tty->ops->close)
-                       for (n = 0; n < closecount; n++)
-                               tty->ops->close(tty, cons_filp);
-       } else if (tty->ops->hangup)
-               (tty->ops->hangup)(tty);
-       /*
-        * We don't want to have driver/ldisc interactions beyond
-        * the ones we did here. The driver layer expects no
-        * calls after ->hangup() from the ldisc side. However we
-        * can't yet guarantee all that.
-        */
-       set_bit(TTY_HUPPED, &tty->flags);
-       tty_ldisc_enable(tty);
-
-       tty_unlock();
-
-       if (f)
-               fput(f);
-}
-
-static void do_tty_hangup(struct work_struct *work)
-{
-       struct tty_struct *tty =
-               container_of(work, struct tty_struct, hangup_work);
-
-       __tty_hangup(tty);
-}
-
-/**
- *     tty_hangup              -       trigger a hangup event
- *     @tty: tty to hangup
- *
- *     A carrier loss (virtual or otherwise) has occurred on this like
- *     schedule a hangup sequence to run after this event.
- */
-
-void tty_hangup(struct tty_struct *tty)
-{
-#ifdef TTY_DEBUG_HANGUP
-       char    buf[64];
-       printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf));
-#endif
-       schedule_work(&tty->hangup_work);
-}
-
-EXPORT_SYMBOL(tty_hangup);
-
-/**
- *     tty_vhangup             -       process vhangup
- *     @tty: tty to hangup
- *
- *     The user has asked via system call for the terminal to be hung up.
- *     We do this synchronously so that when the syscall returns the process
- *     is complete. That guarantee is necessary for security reasons.
- */
-
-void tty_vhangup(struct tty_struct *tty)
-{
-#ifdef TTY_DEBUG_HANGUP
-       char    buf[64];
-
-       printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
-#endif
-       __tty_hangup(tty);
-}
-
-EXPORT_SYMBOL(tty_vhangup);
-
-
-/**
- *     tty_vhangup_self        -       process vhangup for own ctty
- *
- *     Perform a vhangup on the current controlling tty
- */
-
-void tty_vhangup_self(void)
-{
-       struct tty_struct *tty;
-
-       tty = get_current_tty();
-       if (tty) {
-               tty_vhangup(tty);
-               tty_kref_put(tty);
-       }
-}
-
-/**
- *     tty_hung_up_p           -       was tty hung up
- *     @filp: file pointer of tty
- *
- *     Return true if the tty has been subject to a vhangup or a carrier
- *     loss
- */
-
-int tty_hung_up_p(struct file *filp)
-{
-       return (filp->f_op == &hung_up_tty_fops);
-}
-
-EXPORT_SYMBOL(tty_hung_up_p);
-
-static void session_clear_tty(struct pid *session)
-{
-       struct task_struct *p;
-       do_each_pid_task(session, PIDTYPE_SID, p) {
-               proc_clear_tty(p);
-       } while_each_pid_task(session, PIDTYPE_SID, p);
-}
-
-/**
- *     disassociate_ctty       -       disconnect controlling tty
- *     @on_exit: true if exiting so need to "hang up" the session
- *
- *     This function is typically called only by the session leader, when
- *     it wants to disassociate itself from its controlling tty.
- *
- *     It performs the following functions:
- *     (1)  Sends a SIGHUP and SIGCONT to the foreground process group
- *     (2)  Clears the tty from being controlling the session
- *     (3)  Clears the controlling tty for all processes in the
- *             session group.
- *
- *     The argument on_exit is set to 1 if called when a process is
- *     exiting; it is 0 if called by the ioctl TIOCNOTTY.
- *
- *     Locking:
- *             BTM is taken for hysterical raisins, and held when
- *               called from no_tty().
- *               tty_mutex is taken to protect tty
- *               ->siglock is taken to protect ->signal/->sighand
- *               tasklist_lock is taken to walk process list for sessions
- *                 ->siglock is taken to protect ->signal/->sighand
- */
-
-void disassociate_ctty(int on_exit)
-{
-       struct tty_struct *tty;
-       struct pid *tty_pgrp = NULL;
-
-       if (!current->signal->leader)
-               return;
-
-       tty = get_current_tty();
-       if (tty) {
-               tty_pgrp = get_pid(tty->pgrp);
-               if (on_exit) {
-                       if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
-                               tty_vhangup(tty);
-               }
-               tty_kref_put(tty);
-       } else if (on_exit) {
-               struct pid *old_pgrp;
-               spin_lock_irq(&current->sighand->siglock);
-               old_pgrp = current->signal->tty_old_pgrp;
-               current->signal->tty_old_pgrp = NULL;
-               spin_unlock_irq(&current->sighand->siglock);
-               if (old_pgrp) {
-                       kill_pgrp(old_pgrp, SIGHUP, on_exit);
-                       kill_pgrp(old_pgrp, SIGCONT, on_exit);
-                       put_pid(old_pgrp);
-               }
-               return;
-       }
-       if (tty_pgrp) {
-               kill_pgrp(tty_pgrp, SIGHUP, on_exit);
-               if (!on_exit)
-                       kill_pgrp(tty_pgrp, SIGCONT, on_exit);
-               put_pid(tty_pgrp);
-       }
-
-       spin_lock_irq(&current->sighand->siglock);
-       put_pid(current->signal->tty_old_pgrp);
-       current->signal->tty_old_pgrp = NULL;
-       spin_unlock_irq(&current->sighand->siglock);
-
-       tty = get_current_tty();
-       if (tty) {
-               unsigned long flags;
-               spin_lock_irqsave(&tty->ctrl_lock, flags);
-               put_pid(tty->session);
-               put_pid(tty->pgrp);
-               tty->session = NULL;
-               tty->pgrp = NULL;
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               tty_kref_put(tty);
-       } else {
-#ifdef TTY_DEBUG_HANGUP
-               printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
-                      " = NULL", tty);
-#endif
-       }
-
-       /* Now clear signal->tty under the lock */
-       read_lock(&tasklist_lock);
-       session_clear_tty(task_session(current));
-       read_unlock(&tasklist_lock);
-}
-
-/**
- *
- *     no_tty  - Ensure the current process does not have a controlling tty
- */
-void no_tty(void)
-{
-       struct task_struct *tsk = current;
-       tty_lock();
-       disassociate_ctty(0);
-       tty_unlock();
-       proc_clear_tty(tsk);
-}
-
-
-/**
- *     stop_tty        -       propagate flow control
- *     @tty: tty to stop
- *
- *     Perform flow control to the driver. For PTY/TTY pairs we
- *     must also propagate the TIOCKPKT status. May be called
- *     on an already stopped device and will not re-call the driver
- *     method.
- *
- *     This functionality is used by both the line disciplines for
- *     halting incoming flow and by the driver. It may therefore be
- *     called from any context, may be under the tty atomic_write_lock
- *     but not always.
- *
- *     Locking:
- *             Uses the tty control lock internally
- */
-
-void stop_tty(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       if (tty->stopped) {
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               return;
-       }
-       tty->stopped = 1;
-       if (tty->link && tty->link->packet) {
-               tty->ctrl_status &= ~TIOCPKT_START;
-               tty->ctrl_status |= TIOCPKT_STOP;
-               wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
-       }
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-       if (tty->ops->stop)
-               (tty->ops->stop)(tty);
-}
-
-EXPORT_SYMBOL(stop_tty);
-
-/**
- *     start_tty       -       propagate flow control
- *     @tty: tty to start
- *
- *     Start a tty that has been stopped if at all possible. Perform
- *     any necessary wakeups and propagate the TIOCPKT status. If this
- *     is the tty was previous stopped and is being started then the
- *     driver start method is invoked and the line discipline woken.
- *
- *     Locking:
- *             ctrl_lock
- */
-
-void start_tty(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       if (!tty->stopped || tty->flow_stopped) {
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               return;
-       }
-       tty->stopped = 0;
-       if (tty->link && tty->link->packet) {
-               tty->ctrl_status &= ~TIOCPKT_STOP;
-               tty->ctrl_status |= TIOCPKT_START;
-               wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
-       }
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-       if (tty->ops->start)
-               (tty->ops->start)(tty);
-       /* If we have a running line discipline it may need kicking */
-       tty_wakeup(tty);
-}
-
-EXPORT_SYMBOL(start_tty);
-
-/**
- *     tty_read        -       read method for tty device files
- *     @file: pointer to tty file
- *     @buf: user buffer
- *     @count: size of user buffer
- *     @ppos: unused
- *
- *     Perform the read system call function on this terminal device. Checks
- *     for hung up devices before calling the line discipline method.
- *
- *     Locking:
- *             Locks the line discipline internally while needed. Multiple
- *     read calls may be outstanding in parallel.
- */
-
-static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
-                       loff_t *ppos)
-{
-       int i;
-       struct inode *inode = file->f_path.dentry->d_inode;
-       struct tty_struct *tty = file_tty(file);
-       struct tty_ldisc *ld;
-
-       if (tty_paranoia_check(tty, inode, "tty_read"))
-               return -EIO;
-       if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
-               return -EIO;
-
-       /* We want to wait for the line discipline to sort out in this
-          situation */
-       ld = tty_ldisc_ref_wait(tty);
-       if (ld->ops->read)
-               i = (ld->ops->read)(tty, file, buf, count);
-       else
-               i = -EIO;
-       tty_ldisc_deref(ld);
-       if (i > 0)
-               inode->i_atime = current_fs_time(inode->i_sb);
-       return i;
-}
-
-void tty_write_unlock(struct tty_struct *tty)
-{
-       mutex_unlock(&tty->atomic_write_lock);
-       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
-}
-
-int tty_write_lock(struct tty_struct *tty, int ndelay)
-{
-       if (!mutex_trylock(&tty->atomic_write_lock)) {
-               if (ndelay)
-                       return -EAGAIN;
-               if (mutex_lock_interruptible(&tty->atomic_write_lock))
-                       return -ERESTARTSYS;
-       }
-       return 0;
-}
-
-/*
- * Split writes up in sane blocksizes to avoid
- * denial-of-service type attacks
- */
-static inline ssize_t do_tty_write(
-       ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
-       struct tty_struct *tty,
-       struct file *file,
-       const char __user *buf,
-       size_t count)
-{
-       ssize_t ret, written = 0;
-       unsigned int chunk;
-
-       ret = tty_write_lock(tty, file->f_flags & O_NDELAY);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * We chunk up writes into a temporary buffer. This
-        * simplifies low-level drivers immensely, since they
-        * don't have locking issues and user mode accesses.
-        *
-        * But if TTY_NO_WRITE_SPLIT is set, we should use a
-        * big chunk-size..
-        *
-        * The default chunk-size is 2kB, because the NTTY
-        * layer has problems with bigger chunks. It will
-        * claim to be able to handle more characters than
-        * it actually does.
-        *
-        * FIXME: This can probably go away now except that 64K chunks
-        * are too likely to fail unless switched to vmalloc...
-        */
-       chunk = 2048;
-       if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags))
-               chunk = 65536;
-       if (count < chunk)
-               chunk = count;
-
-       /* write_buf/write_cnt is protected by the atomic_write_lock mutex */
-       if (tty->write_cnt < chunk) {
-               unsigned char *buf_chunk;
-
-               if (chunk < 1024)
-                       chunk = 1024;
-
-               buf_chunk = kmalloc(chunk, GFP_KERNEL);
-               if (!buf_chunk) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               kfree(tty->write_buf);
-               tty->write_cnt = chunk;
-               tty->write_buf = buf_chunk;
-       }
-
-       /* Do the write .. */
-       for (;;) {
-               size_t size = count;
-               if (size > chunk)
-                       size = chunk;
-               ret = -EFAULT;
-               if (copy_from_user(tty->write_buf, buf, size))
-                       break;
-               ret = write(tty, file, tty->write_buf, size);
-               if (ret <= 0)
-                       break;
-               written += ret;
-               buf += ret;
-               count -= ret;
-               if (!count)
-                       break;
-               ret = -ERESTARTSYS;
-               if (signal_pending(current))
-                       break;
-               cond_resched();
-       }
-       if (written) {
-               struct inode *inode = file->f_path.dentry->d_inode;
-               inode->i_mtime = current_fs_time(inode->i_sb);
-               ret = written;
-       }
-out:
-       tty_write_unlock(tty);
-       return ret;
-}
-
-/**
- * tty_write_message - write a message to a certain tty, not just the console.
- * @tty: the destination tty_struct
- * @msg: the message to write
- *
- * This is used for messages that need to be redirected to a specific tty.
- * We don't put it into the syslog queue right now maybe in the future if
- * really needed.
- *
- * We must still hold the BTM and test the CLOSING flag for the moment.
- */
-
-void tty_write_message(struct tty_struct *tty, char *msg)
-{
-       if (tty) {
-               mutex_lock(&tty->atomic_write_lock);
-               tty_lock();
-               if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
-                       tty_unlock();
-                       tty->ops->write(tty, msg, strlen(msg));
-               } else
-                       tty_unlock();
-               tty_write_unlock(tty);
-       }
-       return;
-}
-
-
-/**
- *     tty_write               -       write method for tty device file
- *     @file: tty file pointer
- *     @buf: user data to write
- *     @count: bytes to write
- *     @ppos: unused
- *
- *     Write data to a tty device via the line discipline.
- *
- *     Locking:
- *             Locks the line discipline as required
- *             Writes to the tty driver are serialized by the atomic_write_lock
- *     and are then processed in chunks to the device. The line discipline
- *     write method will not be invoked in parallel for each device.
- */
-
-static ssize_t tty_write(struct file *file, const char __user *buf,
-                                               size_t count, loff_t *ppos)
-{
-       struct inode *inode = file->f_path.dentry->d_inode;
-       struct tty_struct *tty = file_tty(file);
-       struct tty_ldisc *ld;
-       ssize_t ret;
-
-       if (tty_paranoia_check(tty, inode, "tty_write"))
-               return -EIO;
-       if (!tty || !tty->ops->write ||
-               (test_bit(TTY_IO_ERROR, &tty->flags)))
-                       return -EIO;
-       /* Short term debug to catch buggy drivers */
-       if (tty->ops->write_room == NULL)
-               printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
-                       tty->driver->name);
-       ld = tty_ldisc_ref_wait(tty);
-       if (!ld->ops->write)
-               ret = -EIO;
-       else
-               ret = do_tty_write(ld->ops->write, tty, file, buf, count);
-       tty_ldisc_deref(ld);
-       return ret;
-}
-
-ssize_t redirected_tty_write(struct file *file, const char __user *buf,
-                                               size_t count, loff_t *ppos)
-{
-       struct file *p = NULL;
-
-       spin_lock(&redirect_lock);
-       if (redirect) {
-               get_file(redirect);
-               p = redirect;
-       }
-       spin_unlock(&redirect_lock);
-
-       if (p) {
-               ssize_t res;
-               res = vfs_write(p, buf, count, &p->f_pos);
-               fput(p);
-               return res;
-       }
-       return tty_write(file, buf, count, ppos);
-}
-
-static char ptychar[] = "pqrstuvwxyzabcde";
-
-/**
- *     pty_line_name   -       generate name for a pty
- *     @driver: the tty driver in use
- *     @index: the minor number
- *     @p: output buffer of at least 6 bytes
- *
- *     Generate a name from a driver reference and write it to the output
- *     buffer.
- *
- *     Locking: None
- */
-static void pty_line_name(struct tty_driver *driver, int index, char *p)
-{
-       int i = index + driver->name_base;
-       /* ->name is initialized to "ttyp", but "tty" is expected */
-       sprintf(p, "%s%c%x",
-               driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name,
-               ptychar[i >> 4 & 0xf], i & 0xf);
-}
-
-/**
- *     tty_line_name   -       generate name for a tty
- *     @driver: the tty driver in use
- *     @index: the minor number
- *     @p: output buffer of at least 7 bytes
- *
- *     Generate a name from a driver reference and write it to the output
- *     buffer.
- *
- *     Locking: None
- */
-static void tty_line_name(struct tty_driver *driver, int index, char *p)
-{
-       sprintf(p, "%s%d", driver->name, index + driver->name_base);
-}
-
-/**
- *     tty_driver_lookup_tty() - find an existing tty, if any
- *     @driver: the driver for the tty
- *     @idx:    the minor number
- *
- *     Return the tty, if found or ERR_PTR() otherwise.
- *
- *     Locking: tty_mutex must be held. If tty is found, the mutex must
- *     be held until the 'fast-open' is also done. Will change once we
- *     have refcounting in the driver and per driver locking
- */
-static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
-               struct inode *inode, int idx)
-{
-       struct tty_struct *tty;
-
-       if (driver->ops->lookup)
-               return driver->ops->lookup(driver, inode, idx);
-
-       tty = driver->ttys[idx];
-       return tty;
-}
-
-/**
- *     tty_init_termios        -  helper for termios setup
- *     @tty: the tty to set up
- *
- *     Initialise the termios structures for this tty. Thus runs under
- *     the tty_mutex currently so we can be relaxed about ordering.
- */
-
-int tty_init_termios(struct tty_struct *tty)
-{
-       struct ktermios *tp;
-       int idx = tty->index;
-
-       tp = tty->driver->termios[idx];
-       if (tp == NULL) {
-               tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-               if (tp == NULL)
-                       return -ENOMEM;
-               memcpy(tp, &tty->driver->init_termios,
-                                               sizeof(struct ktermios));
-               tty->driver->termios[idx] = tp;
-       }
-       tty->termios = tp;
-       tty->termios_locked = tp + 1;
-
-       /* Compatibility until drivers always set this */
-       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
-       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(tty_init_termios);
-
-/**
- *     tty_driver_install_tty() - install a tty entry in the driver
- *     @driver: the driver for the tty
- *     @tty: the tty
- *
- *     Install a tty object into the driver tables. The tty->index field
- *     will be set by the time this is called. This method is responsible
- *     for ensuring any need additional structures are allocated and
- *     configured.
- *
- *     Locking: tty_mutex for now
- */
-static int tty_driver_install_tty(struct tty_driver *driver,
-                                               struct tty_struct *tty)
-{
-       int idx = tty->index;
-       int ret;
-
-       if (driver->ops->install) {
-               ret = driver->ops->install(driver, tty);
-               return ret;
-       }
-
-       if (tty_init_termios(tty) == 0) {
-               tty_driver_kref_get(driver);
-               tty->count++;
-               driver->ttys[idx] = tty;
-               return 0;
-       }
-       return -ENOMEM;
-}
-
-/**
- *     tty_driver_remove_tty() - remove a tty from the driver tables
- *     @driver: the driver for the tty
- *     @idx:    the minor number
- *
- *     Remvoe a tty object from the driver tables. The tty->index field
- *     will be set by the time this is called.
- *
- *     Locking: tty_mutex for now
- */
-static void tty_driver_remove_tty(struct tty_driver *driver,
-                                               struct tty_struct *tty)
-{
-       if (driver->ops->remove)
-               driver->ops->remove(driver, tty);
-       else
-               driver->ttys[tty->index] = NULL;
-}
-
-/*
- *     tty_reopen()    - fast re-open of an open tty
- *     @tty    - the tty to open
- *
- *     Return 0 on success, -errno on error.
- *
- *     Locking: tty_mutex must be held from the time the tty was found
- *              till this open completes.
- */
-static int tty_reopen(struct tty_struct *tty)
-{
-       struct tty_driver *driver = tty->driver;
-
-       if (test_bit(TTY_CLOSING, &tty->flags))
-               return -EIO;
-
-       if (driver->type == TTY_DRIVER_TYPE_PTY &&
-           driver->subtype == PTY_TYPE_MASTER) {
-               /*
-                * special case for PTY masters: only one open permitted,
-                * and the slave side open count is incremented as well.
-                */
-               if (tty->count)
-                       return -EIO;
-
-               tty->link->count++;
-       }
-       tty->count++;
-       tty->driver = driver; /* N.B. why do this every time?? */
-
-       mutex_lock(&tty->ldisc_mutex);
-       WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
-       mutex_unlock(&tty->ldisc_mutex);
-
-       return 0;
-}
-
-/**
- *     tty_init_dev            -       initialise a tty device
- *     @driver: tty driver we are opening a device on
- *     @idx: device index
- *     @ret_tty: returned tty structure
- *     @first_ok: ok to open a new device (used by ptmx)
- *
- *     Prepare a tty device. This may not be a "new" clean device but
- *     could also be an active device. The pty drivers require special
- *     handling because of this.
- *
- *     Locking:
- *             The function is called under the tty_mutex, which
- *     protects us from the tty struct or driver itself going away.
- *
- *     On exit the tty device has the line discipline attached and
- *     a reference count of 1. If a pair was created for pty/tty use
- *     and the other was a pty master then it too has a reference count of 1.
- *
- * WSH 06/09/97: Rewritten to remove races and properly clean up after a
- * failed open.  The new code protects the open with a mutex, so it's
- * really quite straightforward.  The mutex locking can probably be
- * relaxed for the (most common) case of reopening a tty.
- */
-
-struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
-                                                               int first_ok)
-{
-       struct tty_struct *tty;
-       int retval;
-
-       /* Check if pty master is being opened multiple times */
-       if (driver->subtype == PTY_TYPE_MASTER &&
-               (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
-               return ERR_PTR(-EIO);
-       }
-
-       /*
-        * First time open is complex, especially for PTY devices.
-        * This code guarantees that either everything succeeds and the
-        * TTY is ready for operation, or else the table slots are vacated
-        * and the allocated memory released.  (Except that the termios
-        * and locked termios may be retained.)
-        */
-
-       if (!try_module_get(driver->owner))
-               return ERR_PTR(-ENODEV);
-
-       tty = alloc_tty_struct();
-       if (!tty)
-               goto fail_no_mem;
-       initialize_tty_struct(tty, driver, idx);
-
-       retval = tty_driver_install_tty(driver, tty);
-       if (retval < 0) {
-               free_tty_struct(tty);
-               module_put(driver->owner);
-               return ERR_PTR(retval);
-       }
-
-       /*
-        * Structures all installed ... call the ldisc open routines.
-        * If we fail here just call release_tty to clean up.  No need
-        * to decrement the use counts, as release_tty doesn't care.
-        */
-       retval = tty_ldisc_setup(tty, tty->link);
-       if (retval)
-               goto release_mem_out;
-       return tty;
-
-fail_no_mem:
-       module_put(driver->owner);
-       return ERR_PTR(-ENOMEM);
-
-       /* call the tty release_tty routine to clean out this slot */
-release_mem_out:
-       if (printk_ratelimit())
-               printk(KERN_INFO "tty_init_dev: ldisc open failed, "
-                                "clearing slot %d\n", idx);
-       release_tty(tty, idx);
-       return ERR_PTR(retval);
-}
-
-void tty_free_termios(struct tty_struct *tty)
-{
-       struct ktermios *tp;
-       int idx = tty->index;
-       /* Kill this flag and push into drivers for locking etc */
-       if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
-               /* FIXME: Locking on ->termios array */
-               tp = tty->termios;
-               tty->driver->termios[idx] = NULL;
-               kfree(tp);
-       }
-}
-EXPORT_SYMBOL(tty_free_termios);
-
-void tty_shutdown(struct tty_struct *tty)
-{
-       tty_driver_remove_tty(tty->driver, tty);
-       tty_free_termios(tty);
-}
-EXPORT_SYMBOL(tty_shutdown);
-
-/**
- *     release_one_tty         -       release tty structure memory
- *     @kref: kref of tty we are obliterating
- *
- *     Releases memory associated with a tty structure, and clears out the
- *     driver table slots. This function is called when a device is no longer
- *     in use. It also gets called when setup of a device fails.
- *
- *     Locking:
- *             tty_mutex - sometimes only
- *             takes the file list lock internally when working on the list
- *     of ttys that the driver keeps.
- *
- *     This method gets called from a work queue so that the driver private
- *     cleanup ops can sleep (needed for USB at least)
- */
-static void release_one_tty(struct work_struct *work)
-{
-       struct tty_struct *tty =
-               container_of(work, struct tty_struct, hangup_work);
-       struct tty_driver *driver = tty->driver;
-
-       if (tty->ops->cleanup)
-               tty->ops->cleanup(tty);
-
-       tty->magic = 0;
-       tty_driver_kref_put(driver);
-       module_put(driver->owner);
-
-       spin_lock(&tty_files_lock);
-       list_del_init(&tty->tty_files);
-       spin_unlock(&tty_files_lock);
-
-       put_pid(tty->pgrp);
-       put_pid(tty->session);
-       free_tty_struct(tty);
-}
-
-static void queue_release_one_tty(struct kref *kref)
-{
-       struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
-
-       if (tty->ops->shutdown)
-               tty->ops->shutdown(tty);
-       else
-               tty_shutdown(tty);
-
-       /* The hangup queue is now free so we can reuse it rather than
-          waste a chunk of memory for each port */
-       INIT_WORK(&tty->hangup_work, release_one_tty);
-       schedule_work(&tty->hangup_work);
-}
-
-/**
- *     tty_kref_put            -       release a tty kref
- *     @tty: tty device
- *
- *     Release a reference to a tty device and if need be let the kref
- *     layer destruct the object for us
- */
-
-void tty_kref_put(struct tty_struct *tty)
-{
-       if (tty)
-               kref_put(&tty->kref, queue_release_one_tty);
-}
-EXPORT_SYMBOL(tty_kref_put);
-
-/**
- *     release_tty             -       release tty structure memory
- *
- *     Release both @tty and a possible linked partner (think pty pair),
- *     and decrement the refcount of the backing module.
- *
- *     Locking:
- *             tty_mutex - sometimes only
- *             takes the file list lock internally when working on the list
- *     of ttys that the driver keeps.
- *             FIXME: should we require tty_mutex is held here ??
- *
- */
-static void release_tty(struct tty_struct *tty, int idx)
-{
-       /* This should always be true but check for the moment */
-       WARN_ON(tty->index != idx);
-
-       if (tty->link)
-               tty_kref_put(tty->link);
-       tty_kref_put(tty);
-}
-
-/**
- *     tty_release             -       vfs callback for close
- *     @inode: inode of tty
- *     @filp: file pointer for handle to tty
- *
- *     Called the last time each file handle is closed that references
- *     this tty. There may however be several such references.
- *
- *     Locking:
- *             Takes bkl. See tty_release_dev
- *
- * Even releasing the tty structures is a tricky business.. We have
- * to be very careful that the structures are all released at the
- * same time, as interrupts might otherwise get the wrong pointers.
- *
- * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
- * lead to double frees or releasing memory still in use.
- */
-
-int tty_release(struct inode *inode, struct file *filp)
-{
-       struct tty_struct *tty = file_tty(filp);
-       struct tty_struct *o_tty;
-       int     pty_master, tty_closing, o_tty_closing, do_sleep;
-       int     devpts;
-       int     idx;
-       char    buf[64];
-
-       if (tty_paranoia_check(tty, inode, "tty_release_dev"))
-               return 0;
-
-       tty_lock();
-       check_tty_count(tty, "tty_release_dev");
-
-       __tty_fasync(-1, filp, 0);
-
-       idx = tty->index;
-       pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-                     tty->driver->subtype == PTY_TYPE_MASTER);
-       devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
-       o_tty = tty->link;
-
-#ifdef TTY_PARANOIA_CHECK
-       if (idx < 0 || idx >= tty->driver->num) {
-               printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
-                                 "free (%s)\n", tty->name);
-               tty_unlock();
-               return 0;
-       }
-       if (!devpts) {
-               if (tty != tty->driver->ttys[idx]) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
-                              "for (%s)\n", idx, tty->name);
-                       return 0;
-               }
-               if (tty->termios != tty->driver->termios[idx]) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
-                              "for (%s)\n",
-                              idx, tty->name);
-                       return 0;
-               }
-       }
-#endif
-
-#ifdef TTY_DEBUG_HANGUP
-       printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...",
-              tty_name(tty, buf), tty->count);
-#endif
-
-#ifdef TTY_PARANOIA_CHECK
-       if (tty->driver->other &&
-            !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
-               if (o_tty != tty->driver->other->ttys[idx]) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
-                                         "not o_tty for (%s)\n",
-                              idx, tty->name);
-                       return 0 ;
-               }
-               if (o_tty->termios != tty->driver->other->termios[idx]) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
-                                         "not o_termios for (%s)\n",
-                              idx, tty->name);
-                       return 0;
-               }
-               if (o_tty->link != tty) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
-                       return 0;
-               }
-       }
-#endif
-       if (tty->ops->close)
-               tty->ops->close(tty, filp);
-
-       tty_unlock();
-       /*
-        * Sanity check: if tty->count is going to zero, there shouldn't be
-        * any waiters on tty->read_wait or tty->write_wait.  We test the
-        * wait queues and kick everyone out _before_ actually starting to
-        * close.  This ensures that we won't block while releasing the tty
-        * structure.
-        *
-        * The test for the o_tty closing is necessary, since the master and
-        * slave sides may close in any order.  If the slave side closes out
-        * first, its count will be one, since the master side holds an open.
-        * Thus this test wouldn't be triggered at the time the slave closes,
-        * so we do it now.
-        *
-        * Note that it's possible for the tty to be opened again while we're
-        * flushing out waiters.  By recalculating the closing flags before
-        * each iteration we avoid any problems.
-        */
-       while (1) {
-               /* Guard against races with tty->count changes elsewhere and
-                  opens on /dev/tty */
-
-               mutex_lock(&tty_mutex);
-               tty_lock();
-               tty_closing = tty->count <= 1;
-               o_tty_closing = o_tty &&
-                       (o_tty->count <= (pty_master ? 1 : 0));
-               do_sleep = 0;
-
-               if (tty_closing) {
-                       if (waitqueue_active(&tty->read_wait)) {
-                               wake_up_poll(&tty->read_wait, POLLIN);
-                               do_sleep++;
-                       }
-                       if (waitqueue_active(&tty->write_wait)) {
-                               wake_up_poll(&tty->write_wait, POLLOUT);
-                               do_sleep++;
-                       }
-               }
-               if (o_tty_closing) {
-                       if (waitqueue_active(&o_tty->read_wait)) {
-                               wake_up_poll(&o_tty->read_wait, POLLIN);
-                               do_sleep++;
-                       }
-                       if (waitqueue_active(&o_tty->write_wait)) {
-                               wake_up_poll(&o_tty->write_wait, POLLOUT);
-                               do_sleep++;
-                       }
-               }
-               if (!do_sleep)
-                       break;
-
-               printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
-                                   "active!\n", tty_name(tty, buf));
-               tty_unlock();
-               mutex_unlock(&tty_mutex);
-               schedule();
-       }
-
-       /*
-        * The closing flags are now consistent with the open counts on
-        * both sides, and we've completed the last operation that could
-        * block, so it's safe to proceed with closing.
-        */
-       if (pty_master) {
-               if (--o_tty->count < 0) {
-                       printk(KERN_WARNING "tty_release_dev: bad pty slave count "
-                                           "(%d) for %s\n",
-                              o_tty->count, tty_name(o_tty, buf));
-                       o_tty->count = 0;
-               }
-       }
-       if (--tty->count < 0) {
-               printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
-                      tty->count, tty_name(tty, buf));
-               tty->count = 0;
-       }
-
-       /*
-        * We've decremented tty->count, so we need to remove this file
-        * descriptor off the tty->tty_files list; this serves two
-        * purposes:
-        *  - check_tty_count sees the correct number of file descriptors
-        *    associated with this tty.
-        *  - do_tty_hangup no longer sees this file descriptor as
-        *    something that needs to be handled for hangups.
-        */
-       tty_del_file(filp);
-
-       /*
-        * Perform some housekeeping before deciding whether to return.
-        *
-        * Set the TTY_CLOSING flag if this was the last open.  In the
-        * case of a pty we may have to wait around for the other side
-        * to close, and TTY_CLOSING makes sure we can't be reopened.
-        */
-       if (tty_closing)
-               set_bit(TTY_CLOSING, &tty->flags);
-       if (o_tty_closing)
-               set_bit(TTY_CLOSING, &o_tty->flags);
-
-       /*
-        * If _either_ side is closing, make sure there aren't any
-        * processes that still think tty or o_tty is their controlling
-        * tty.
-        */
-       if (tty_closing || o_tty_closing) {
-               read_lock(&tasklist_lock);
-               session_clear_tty(tty->session);
-               if (o_tty)
-                       session_clear_tty(o_tty->session);
-               read_unlock(&tasklist_lock);
-       }
-
-       mutex_unlock(&tty_mutex);
-
-       /* check whether both sides are closing ... */
-       if (!tty_closing || (o_tty && !o_tty_closing)) {
-               tty_unlock();
-               return 0;
-       }
-
-#ifdef TTY_DEBUG_HANGUP
-       printk(KERN_DEBUG "freeing tty structure...");
-#endif
-       /*
-        * Ask the line discipline code to release its structures
-        */
-       tty_ldisc_release(tty, o_tty);
-       /*
-        * The release_tty function takes care of the details of clearing
-        * the slots and preserving the termios structure.
-        */
-       release_tty(tty, idx);
-
-       /* Make this pty number available for reallocation */
-       if (devpts)
-               devpts_kill_index(inode, idx);
-       tty_unlock();
-       return 0;
-}
-
-/**
- *     tty_open                -       open a tty device
- *     @inode: inode of device file
- *     @filp: file pointer to tty
- *
- *     tty_open and tty_release keep up the tty count that contains the
- *     number of opens done on a tty. We cannot use the inode-count, as
- *     different inodes might point to the same tty.
- *
- *     Open-counting is needed for pty masters, as well as for keeping
- *     track of serial lines: DTR is dropped when the last close happens.
- *     (This is not done solely through tty->count, now.  - Ted 1/27/92)
- *
- *     The termios state of a pty is reset on first open so that
- *     settings don't persist across reuse.
- *
- *     Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work.
- *              tty->count should protect the rest.
- *              ->siglock protects ->signal/->sighand
- */
-
-static int tty_open(struct inode *inode, struct file *filp)
-{
-       struct tty_struct *tty = NULL;
-       int noctty, retval;
-       struct tty_driver *driver;
-       int index;
-       dev_t device = inode->i_rdev;
-       unsigned saved_flags = filp->f_flags;
-
-       nonseekable_open(inode, filp);
-
-retry_open:
-       noctty = filp->f_flags & O_NOCTTY;
-       index  = -1;
-       retval = 0;
-
-       mutex_lock(&tty_mutex);
-       tty_lock();
-
-       if (device == MKDEV(TTYAUX_MAJOR, 0)) {
-               tty = get_current_tty();
-               if (!tty) {
-                       tty_unlock();
-                       mutex_unlock(&tty_mutex);
-                       return -ENXIO;
-               }
-               driver = tty_driver_kref_get(tty->driver);
-               index = tty->index;
-               filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
-               /* noctty = 1; */
-               /* FIXME: Should we take a driver reference ? */
-               tty_kref_put(tty);
-               goto got_driver;
-       }
-#ifdef CONFIG_VT
-       if (device == MKDEV(TTY_MAJOR, 0)) {
-               extern struct tty_driver *console_driver;
-               driver = tty_driver_kref_get(console_driver);
-               index = fg_console;
-               noctty = 1;
-               goto got_driver;
-       }
-#endif
-       if (device == MKDEV(TTYAUX_MAJOR, 1)) {
-               struct tty_driver *console_driver = console_device(&index);
-               if (console_driver) {
-                       driver = tty_driver_kref_get(console_driver);
-                       if (driver) {
-                               /* Don't let /dev/console block */
-                               filp->f_flags |= O_NONBLOCK;
-                               noctty = 1;
-                               goto got_driver;
-                       }
-               }
-               tty_unlock();
-               mutex_unlock(&tty_mutex);
-               return -ENODEV;
-       }
-
-       driver = get_tty_driver(device, &index);
-       if (!driver) {
-               tty_unlock();
-               mutex_unlock(&tty_mutex);
-               return -ENODEV;
-       }
-got_driver:
-       if (!tty) {
-               /* check whether we're reopening an existing tty */
-               tty = tty_driver_lookup_tty(driver, inode, index);
-
-               if (IS_ERR(tty)) {
-                       tty_unlock();
-                       mutex_unlock(&tty_mutex);
-                       return PTR_ERR(tty);
-               }
-       }
-
-       if (tty) {
-               retval = tty_reopen(tty);
-               if (retval)
-                       tty = ERR_PTR(retval);
-       } else
-               tty = tty_init_dev(driver, index, 0);
-
-       mutex_unlock(&tty_mutex);
-       tty_driver_kref_put(driver);
-       if (IS_ERR(tty)) {
-               tty_unlock();
-               return PTR_ERR(tty);
-       }
-
-       retval = tty_add_file(tty, filp);
-       if (retval) {
-               tty_unlock();
-               return retval;
-       }
-
-       check_tty_count(tty, "tty_open");
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->driver->subtype == PTY_TYPE_MASTER)
-               noctty = 1;
-#ifdef TTY_DEBUG_HANGUP
-       printk(KERN_DEBUG "opening %s...", tty->name);
-#endif
-       if (!retval) {
-               if (tty->ops->open)
-                       retval = tty->ops->open(tty, filp);
-               else
-                       retval = -ENODEV;
-       }
-       filp->f_flags = saved_flags;
-
-       if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) &&
-                                               !capable(CAP_SYS_ADMIN))
-               retval = -EBUSY;
-
-       if (retval) {
-#ifdef TTY_DEBUG_HANGUP
-               printk(KERN_DEBUG "error %d in opening %s...", retval,
-                      tty->name);
-#endif
-               tty_unlock(); /* need to call tty_release without BTM */
-               tty_release(inode, filp);
-               if (retval != -ERESTARTSYS)
-                       return retval;
-
-               if (signal_pending(current))
-                       return retval;
-
-               schedule();
-               /*
-                * Need to reset f_op in case a hangup happened.
-                */
-               tty_lock();
-               if (filp->f_op == &hung_up_tty_fops)
-                       filp->f_op = &tty_fops;
-               tty_unlock();
-               goto retry_open;
-       }
-       tty_unlock();
-
-
-       mutex_lock(&tty_mutex);
-       tty_lock();
-       spin_lock_irq(&current->sighand->siglock);
-       if (!noctty &&
-           current->signal->leader &&
-           !current->signal->tty &&
-           tty->session == NULL)
-               __proc_set_tty(current, tty);
-       spin_unlock_irq(&current->sighand->siglock);
-       tty_unlock();
-       mutex_unlock(&tty_mutex);
-       return 0;
-}
-
-
-
-/**
- *     tty_poll        -       check tty status
- *     @filp: file being polled
- *     @wait: poll wait structures to update
- *
- *     Call the line discipline polling method to obtain the poll
- *     status of the device.
- *
- *     Locking: locks called line discipline but ldisc poll method
- *     may be re-entered freely by other callers.
- */
-
-static unsigned int tty_poll(struct file *filp, poll_table *wait)
-{
-       struct tty_struct *tty = file_tty(filp);
-       struct tty_ldisc *ld;
-       int ret = 0;
-
-       if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll"))
-               return 0;
-
-       ld = tty_ldisc_ref_wait(tty);
-       if (ld->ops->poll)
-               ret = (ld->ops->poll)(tty, filp, wait);
-       tty_ldisc_deref(ld);
-       return ret;
-}
-
-static int __tty_fasync(int fd, struct file *filp, int on)
-{
-       struct tty_struct *tty = file_tty(filp);
-       unsigned long flags;
-       int retval = 0;
-
-       if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync"))
-               goto out;
-
-       retval = fasync_helper(fd, filp, on, &tty->fasync);
-       if (retval <= 0)
-               goto out;
-
-       if (on) {
-               enum pid_type type;
-               struct pid *pid;
-               if (!waitqueue_active(&tty->read_wait))
-                       tty->minimum_to_wake = 1;
-               spin_lock_irqsave(&tty->ctrl_lock, flags);
-               if (tty->pgrp) {
-                       pid = tty->pgrp;
-                       type = PIDTYPE_PGID;
-               } else {
-                       pid = task_pid(current);
-                       type = PIDTYPE_PID;
-               }
-               get_pid(pid);
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               retval = __f_setown(filp, pid, type, 0);
-               put_pid(pid);
-               if (retval)
-                       goto out;
-       } else {
-               if (!tty->fasync && !waitqueue_active(&tty->read_wait))
-                       tty->minimum_to_wake = N_TTY_BUF_SIZE;
-       }
-       retval = 0;
-out:
-       return retval;
-}
-
-static int tty_fasync(int fd, struct file *filp, int on)
-{
-       int retval;
-       tty_lock();
-       retval = __tty_fasync(fd, filp, on);
-       tty_unlock();
-       return retval;
-}
-
-/**
- *     tiocsti                 -       fake input character
- *     @tty: tty to fake input into
- *     @p: pointer to character
- *
- *     Fake input to a tty device. Does the necessary locking and
- *     input management.
- *
- *     FIXME: does not honour flow control ??
- *
- *     Locking:
- *             Called functions take tty_ldisc_lock
- *             current->signal->tty check is safe without locks
- *
- *     FIXME: may race normal receive processing
- */
-
-static int tiocsti(struct tty_struct *tty, char __user *p)
-{
-       char ch, mbz = 0;
-       struct tty_ldisc *ld;
-
-       if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       if (get_user(ch, p))
-               return -EFAULT;
-       tty_audit_tiocsti(tty, ch);
-       ld = tty_ldisc_ref_wait(tty);
-       ld->ops->receive_buf(tty, &ch, &mbz, 1);
-       tty_ldisc_deref(ld);
-       return 0;
-}
-
-/**
- *     tiocgwinsz              -       implement window query ioctl
- *     @tty; tty
- *     @arg: user buffer for result
- *
- *     Copies the kernel idea of the window size into the user buffer.
- *
- *     Locking: tty->termios_mutex is taken to ensure the winsize data
- *             is consistent.
- */
-
-static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
-{
-       int err;
-
-       mutex_lock(&tty->termios_mutex);
-       err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
-       mutex_unlock(&tty->termios_mutex);
-
-       return err ? -EFAULT: 0;
-}
-
-/**
- *     tty_do_resize           -       resize event
- *     @tty: tty being resized
- *     @rows: rows (character)
- *     @cols: cols (character)
- *
- *     Update the termios variables and send the necessary signals to
- *     peform a terminal resize correctly
- */
-
-int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
-{
-       struct pid *pgrp;
-       unsigned long flags;
-
-       /* Lock the tty */
-       mutex_lock(&tty->termios_mutex);
-       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
-               goto done;
-       /* Get the PID values and reference them so we can
-          avoid holding the tty ctrl lock while sending signals */
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       pgrp = get_pid(tty->pgrp);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-       if (pgrp)
-               kill_pgrp(pgrp, SIGWINCH, 1);
-       put_pid(pgrp);
-
-       tty->winsize = *ws;
-done:
-       mutex_unlock(&tty->termios_mutex);
-       return 0;
-}
-
-/**
- *     tiocswinsz              -       implement window size set ioctl
- *     @tty; tty side of tty
- *     @arg: user buffer for result
- *
- *     Copies the user idea of the window size to the kernel. Traditionally
- *     this is just advisory information but for the Linux console it
- *     actually has driver level meaning and triggers a VC resize.
- *
- *     Locking:
- *             Driver dependant. The default do_resize method takes the
- *     tty termios mutex and ctrl_lock. The console takes its own lock
- *     then calls into the default method.
- */
-
-static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg)
-{
-       struct winsize tmp_ws;
-       if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
-               return -EFAULT;
-
-       if (tty->ops->resize)
-               return tty->ops->resize(tty, &tmp_ws);
-       else
-               return tty_do_resize(tty, &tmp_ws);
-}
-
-/**
- *     tioccons        -       allow admin to move logical console
- *     @file: the file to become console
- *
- *     Allow the adminstrator to move the redirected console device
- *
- *     Locking: uses redirect_lock to guard the redirect information
- */
-
-static int tioccons(struct file *file)
-{
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       if (file->f_op->write == redirected_tty_write) {
-               struct file *f;
-               spin_lock(&redirect_lock);
-               f = redirect;
-               redirect = NULL;
-               spin_unlock(&redirect_lock);
-               if (f)
-                       fput(f);
-               return 0;
-       }
-       spin_lock(&redirect_lock);
-       if (redirect) {
-               spin_unlock(&redirect_lock);
-               return -EBUSY;
-       }
-       get_file(file);
-       redirect = file;
-       spin_unlock(&redirect_lock);
-       return 0;
-}
-
-/**
- *     fionbio         -       non blocking ioctl
- *     @file: file to set blocking value
- *     @p: user parameter
- *
- *     Historical tty interfaces had a blocking control ioctl before
- *     the generic functionality existed. This piece of history is preserved
- *     in the expected tty API of posix OS's.
- *
- *     Locking: none, the open file handle ensures it won't go away.
- */
-
-static int fionbio(struct file *file, int __user *p)
-{
-       int nonblock;
-
-       if (get_user(nonblock, p))
-               return -EFAULT;
-
-       spin_lock(&file->f_lock);
-       if (nonblock)
-               file->f_flags |= O_NONBLOCK;
-       else
-               file->f_flags &= ~O_NONBLOCK;
-       spin_unlock(&file->f_lock);
-       return 0;
-}
-
-/**
- *     tiocsctty       -       set controlling tty
- *     @tty: tty structure
- *     @arg: user argument
- *
- *     This ioctl is used to manage job control. It permits a session
- *     leader to set this tty as the controlling tty for the session.
- *
- *     Locking:
- *             Takes tty_mutex() to protect tty instance
- *             Takes tasklist_lock internally to walk sessions
- *             Takes ->siglock() when updating signal->tty
- */
-
-static int tiocsctty(struct tty_struct *tty, int arg)
-{
-       int ret = 0;
-       if (current->signal->leader && (task_session(current) == tty->session))
-               return ret;
-
-       mutex_lock(&tty_mutex);
-       /*
-        * The process must be a session leader and
-        * not have a controlling tty already.
-        */
-       if (!current->signal->leader || current->signal->tty) {
-               ret = -EPERM;
-               goto unlock;
-       }
-
-       if (tty->session) {
-               /*
-                * This tty is already the controlling
-                * tty for another session group!
-                */
-               if (arg == 1 && capable(CAP_SYS_ADMIN)) {
-                       /*
-                        * Steal it away
-                        */
-                       read_lock(&tasklist_lock);
-                       session_clear_tty(tty->session);
-                       read_unlock(&tasklist_lock);
-               } else {
-                       ret = -EPERM;
-                       goto unlock;
-               }
-       }
-       proc_set_tty(current, tty);
-unlock:
-       mutex_unlock(&tty_mutex);
-       return ret;
-}
-
-/**
- *     tty_get_pgrp    -       return a ref counted pgrp pid
- *     @tty: tty to read
- *
- *     Returns a refcounted instance of the pid struct for the process
- *     group controlling the tty.
- */
-
-struct pid *tty_get_pgrp(struct tty_struct *tty)
-{
-       unsigned long flags;
-       struct pid *pgrp;
-
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       pgrp = get_pid(tty->pgrp);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-       return pgrp;
-}
-EXPORT_SYMBOL_GPL(tty_get_pgrp);
-
-/**
- *     tiocgpgrp               -       get process group
- *     @tty: tty passed by user
- *     @real_tty: tty side of the tty pased by the user if a pty else the tty
- *     @p: returned pid
- *
- *     Obtain the process group of the tty. If there is no process group
- *     return an error.
- *
- *     Locking: none. Reference to current->signal->tty is safe.
- */
-
-static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
-       struct pid *pid;
-       int ret;
-       /*
-        * (tty == real_tty) is a cheap way of
-        * testing if the tty is NOT a master pty.
-        */
-       if (tty == real_tty && current->signal->tty != real_tty)
-               return -ENOTTY;
-       pid = tty_get_pgrp(real_tty);
-       ret =  put_user(pid_vnr(pid), p);
-       put_pid(pid);
-       return ret;
-}
-
-/**
- *     tiocspgrp               -       attempt to set process group
- *     @tty: tty passed by user
- *     @real_tty: tty side device matching tty passed by user
- *     @p: pid pointer
- *
- *     Set the process group of the tty to the session passed. Only
- *     permitted where the tty session is our session.
- *
- *     Locking: RCU, ctrl lock
- */
-
-static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
-       struct pid *pgrp;
-       pid_t pgrp_nr;
-       int retval = tty_check_change(real_tty);
-       unsigned long flags;
-
-       if (retval == -EIO)
-               return -ENOTTY;
-       if (retval)
-               return retval;
-       if (!current->signal->tty ||
-           (current->signal->tty != real_tty) ||
-           (real_tty->session != task_session(current)))
-               return -ENOTTY;
-       if (get_user(pgrp_nr, p))
-               return -EFAULT;
-       if (pgrp_nr < 0)
-               return -EINVAL;
-       rcu_read_lock();
-       pgrp = find_vpid(pgrp_nr);
-       retval = -ESRCH;
-       if (!pgrp)
-               goto out_unlock;
-       retval = -EPERM;
-       if (session_of_pgrp(pgrp) != task_session(current))
-               goto out_unlock;
-       retval = 0;
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       put_pid(real_tty->pgrp);
-       real_tty->pgrp = get_pid(pgrp);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-out_unlock:
-       rcu_read_unlock();
-       return retval;
-}
-
-/**
- *     tiocgsid                -       get session id
- *     @tty: tty passed by user
- *     @real_tty: tty side of the tty pased by the user if a pty else the tty
- *     @p: pointer to returned session id
- *
- *     Obtain the session id of the tty. If there is no session
- *     return an error.
- *
- *     Locking: none. Reference to current->signal->tty is safe.
- */
-
-static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
-       /*
-        * (tty == real_tty) is a cheap way of
-        * testing if the tty is NOT a master pty.
-       */
-       if (tty == real_tty && current->signal->tty != real_tty)
-               return -ENOTTY;
-       if (!real_tty->session)
-               return -ENOTTY;
-       return put_user(pid_vnr(real_tty->session), p);
-}
-
-/**
- *     tiocsetd        -       set line discipline
- *     @tty: tty device
- *     @p: pointer to user data
- *
- *     Set the line discipline according to user request.
- *
- *     Locking: see tty_set_ldisc, this function is just a helper
- */
-
-static int tiocsetd(struct tty_struct *tty, int __user *p)
-{
-       int ldisc;
-       int ret;
-
-       if (get_user(ldisc, p))
-               return -EFAULT;
-
-       ret = tty_set_ldisc(tty, ldisc);
-
-       return ret;
-}
-
-/**
- *     send_break      -       performed time break
- *     @tty: device to break on
- *     @duration: timeout in mS
- *
- *     Perform a timed break on hardware that lacks its own driver level
- *     timed break functionality.
- *
- *     Locking:
- *             atomic_write_lock serializes
- *
- */
-
-static int send_break(struct tty_struct *tty, unsigned int duration)
-{
-       int retval;
-
-       if (tty->ops->break_ctl == NULL)
-               return 0;
-
-       if (tty->driver->flags & TTY_DRIVER_HARDWARE_BREAK)
-               retval = tty->ops->break_ctl(tty, duration);
-       else {
-               /* Do the work ourselves */
-               if (tty_write_lock(tty, 0) < 0)
-                       return -EINTR;
-               retval = tty->ops->break_ctl(tty, -1);
-               if (retval)
-                       goto out;
-               if (!signal_pending(current))
-                       msleep_interruptible(duration);
-               retval = tty->ops->break_ctl(tty, 0);
-out:
-               tty_write_unlock(tty);
-               if (signal_pending(current))
-                       retval = -EINTR;
-       }
-       return retval;
-}
-
-/**
- *     tty_tiocmget            -       get modem status
- *     @tty: tty device
- *     @file: user file pointer
- *     @p: pointer to result
- *
- *     Obtain the modem status bits from the tty driver if the feature
- *     is supported. Return -EINVAL if it is not available.
- *
- *     Locking: none (up to the driver)
- */
-
-static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p)
-{
-       int retval = -EINVAL;
-
-       if (tty->ops->tiocmget) {
-               retval = tty->ops->tiocmget(tty, file);
-
-               if (retval >= 0)
-                       retval = put_user(retval, p);
-       }
-       return retval;
-}
-
-/**
- *     tty_tiocmset            -       set modem status
- *     @tty: tty device
- *     @file: user file pointer
- *     @cmd: command - clear bits, set bits or set all
- *     @p: pointer to desired bits
- *
- *     Set the modem status bits from the tty driver if the feature
- *     is supported. Return -EINVAL if it is not available.
- *
- *     Locking: none (up to the driver)
- */
-
-static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd,
-            unsigned __user *p)
-{
-       int retval;
-       unsigned int set, clear, val;
-
-       if (tty->ops->tiocmset == NULL)
-               return -EINVAL;
-
-       retval = get_user(val, p);
-       if (retval)
-               return retval;
-       set = clear = 0;
-       switch (cmd) {
-       case TIOCMBIS:
-               set = val;
-               break;
-       case TIOCMBIC:
-               clear = val;
-               break;
-       case TIOCMSET:
-               set = val;
-               clear = ~val;
-               break;
-       }
-       set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
-       clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
-       return tty->ops->tiocmset(tty, file, set, clear);
-}
-
-static int tty_tiocgicount(struct tty_struct *tty, void __user *arg)
-{
-       int retval = -EINVAL;
-       struct serial_icounter_struct icount;
-       memset(&icount, 0, sizeof(icount));
-       if (tty->ops->get_icount)
-               retval = tty->ops->get_icount(tty, &icount);
-       if (retval != 0)
-               return retval;
-       if (copy_to_user(arg, &icount, sizeof(icount)))
-               return -EFAULT;
-       return 0;
-}
-
-struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
-{
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->driver->subtype == PTY_TYPE_MASTER)
-               tty = tty->link;
-       return tty;
-}
-EXPORT_SYMBOL(tty_pair_get_tty);
-
-struct tty_struct *tty_pair_get_pty(struct tty_struct *tty)
-{
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->driver->subtype == PTY_TYPE_MASTER)
-           return tty;
-       return tty->link;
-}
-EXPORT_SYMBOL(tty_pair_get_pty);
-
-/*
- * Split this up, as gcc can choke on it otherwise..
- */
-long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct tty_struct *tty = file_tty(file);
-       struct tty_struct *real_tty;
-       void __user *p = (void __user *)arg;
-       int retval;
-       struct tty_ldisc *ld;
-       struct inode *inode = file->f_dentry->d_inode;
-
-       if (tty_paranoia_check(tty, inode, "tty_ioctl"))
-               return -EINVAL;
-
-       real_tty = tty_pair_get_tty(tty);
-
-       /*
-        * Factor out some common prep work
-        */
-       switch (cmd) {
-       case TIOCSETD:
-       case TIOCSBRK:
-       case TIOCCBRK:
-       case TCSBRK:
-       case TCSBRKP:
-               retval = tty_check_change(tty);
-               if (retval)
-                       return retval;
-               if (cmd != TIOCCBRK) {
-                       tty_wait_until_sent(tty, 0);
-                       if (signal_pending(current))
-                               return -EINTR;
-               }
-               break;
-       }
-
-       /*
-        *      Now do the stuff.
-        */
-       switch (cmd) {
-       case TIOCSTI:
-               return tiocsti(tty, p);
-       case TIOCGWINSZ:
-               return tiocgwinsz(real_tty, p);
-       case TIOCSWINSZ:
-               return tiocswinsz(real_tty, p);
-       case TIOCCONS:
-               return real_tty != tty ? -EINVAL : tioccons(file);
-       case FIONBIO:
-               return fionbio(file, p);
-       case TIOCEXCL:
-               set_bit(TTY_EXCLUSIVE, &tty->flags);
-               return 0;
-       case TIOCNXCL:
-               clear_bit(TTY_EXCLUSIVE, &tty->flags);
-               return 0;
-       case TIOCNOTTY:
-               if (current->signal->tty != tty)
-                       return -ENOTTY;
-               no_tty();
-               return 0;
-       case TIOCSCTTY:
-               return tiocsctty(tty, arg);
-       case TIOCGPGRP:
-               return tiocgpgrp(tty, real_tty, p);
-       case TIOCSPGRP:
-               return tiocspgrp(tty, real_tty, p);
-       case TIOCGSID:
-               return tiocgsid(tty, real_tty, p);
-       case TIOCGETD:
-               return put_user(tty->ldisc->ops->num, (int __user *)p);
-       case TIOCSETD:
-               return tiocsetd(tty, p);
-       /*
-        * Break handling
-        */
-       case TIOCSBRK:  /* Turn break on, unconditionally */
-               if (tty->ops->break_ctl)
-                       return tty->ops->break_ctl(tty, -1);
-               return 0;
-       case TIOCCBRK:  /* Turn break off, unconditionally */
-               if (tty->ops->break_ctl)
-                       return tty->ops->break_ctl(tty, 0);
-               return 0;
-       case TCSBRK:   /* SVID version: non-zero arg --> no break */
-               /* non-zero arg means wait for all output data
-                * to be sent (performed above) but don't send break.
-                * This is used by the tcdrain() termios function.
-                */
-               if (!arg)
-                       return send_break(tty, 250);
-               return 0;
-       case TCSBRKP:   /* support for POSIX tcsendbreak() */
-               return send_break(tty, arg ? arg*100 : 250);
-
-       case TIOCMGET:
-               return tty_tiocmget(tty, file, p);
-       case TIOCMSET:
-       case TIOCMBIC:
-       case TIOCMBIS:
-               return tty_tiocmset(tty, file, cmd, p);
-       case TIOCGICOUNT:
-               retval = tty_tiocgicount(tty, p);
-               /* For the moment allow fall through to the old method */
-               if (retval != -EINVAL)
-                       return retval;
-               break;
-       case TCFLSH:
-               switch (arg) {
-               case TCIFLUSH:
-               case TCIOFLUSH:
-               /* flush tty buffer and allow ldisc to process ioctl */
-                       tty_buffer_flush(tty);
-                       break;
-               }
-               break;
-       }
-       if (tty->ops->ioctl) {
-               retval = (tty->ops->ioctl)(tty, file, cmd, arg);
-               if (retval != -ENOIOCTLCMD)
-                       return retval;
-       }
-       ld = tty_ldisc_ref_wait(tty);
-       retval = -EINVAL;
-       if (ld->ops->ioctl) {
-               retval = ld->ops->ioctl(tty, file, cmd, arg);
-               if (retval == -ENOIOCTLCMD)
-                       retval = -EINVAL;
-       }
-       tty_ldisc_deref(ld);
-       return retval;
-}
-
-#ifdef CONFIG_COMPAT
-static long tty_compat_ioctl(struct file *file, unsigned int cmd,
-                               unsigned long arg)
-{
-       struct inode *inode = file->f_dentry->d_inode;
-       struct tty_struct *tty = file_tty(file);
-       struct tty_ldisc *ld;
-       int retval = -ENOIOCTLCMD;
-
-       if (tty_paranoia_check(tty, inode, "tty_ioctl"))
-               return -EINVAL;
-
-       if (tty->ops->compat_ioctl) {
-               retval = (tty->ops->compat_ioctl)(tty, file, cmd, arg);
-               if (retval != -ENOIOCTLCMD)
-                       return retval;
-       }
-
-       ld = tty_ldisc_ref_wait(tty);
-       if (ld->ops->compat_ioctl)
-               retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
-       tty_ldisc_deref(ld);
-
-       return retval;
-}
-#endif
-
-/*
- * This implements the "Secure Attention Key" ---  the idea is to
- * prevent trojan horses by killing all processes associated with this
- * tty when the user hits the "Secure Attention Key".  Required for
- * super-paranoid applications --- see the Orange Book for more details.
- *
- * This code could be nicer; ideally it should send a HUP, wait a few
- * seconds, then send a INT, and then a KILL signal.  But you then
- * have to coordinate with the init process, since all processes associated
- * with the current tty must be dead before the new getty is allowed
- * to spawn.
- *
- * Now, if it would be correct ;-/ The current code has a nasty hole -
- * it doesn't catch files in flight. We may send the descriptor to ourselves
- * via AF_UNIX socket, close it and later fetch from socket. FIXME.
- *
- * Nasty bug: do_SAK is being called in interrupt context.  This can
- * deadlock.  We punt it up to process context.  AKPM - 16Mar2001
- */
-void __do_SAK(struct tty_struct *tty)
-{
-#ifdef TTY_SOFT_SAK
-       tty_hangup(tty);
-#else
-       struct task_struct *g, *p;
-       struct pid *session;
-       int             i;
-       struct file     *filp;
-       struct fdtable *fdt;
-
-       if (!tty)
-               return;
-       session = tty->session;
-
-       tty_ldisc_flush(tty);
-
-       tty_driver_flush_buffer(tty);
-
-       read_lock(&tasklist_lock);
-       /* Kill the entire session */
-       do_each_pid_task(session, PIDTYPE_SID, p) {
-               printk(KERN_NOTICE "SAK: killed process %d"
-                       " (%s): task_session(p)==tty->session\n",
-                       task_pid_nr(p), p->comm);
-               send_sig(SIGKILL, p, 1);
-       } while_each_pid_task(session, PIDTYPE_SID, p);
-       /* Now kill any processes that happen to have the
-        * tty open.
-        */
-       do_each_thread(g, p) {
-               if (p->signal->tty == tty) {
-                       printk(KERN_NOTICE "SAK: killed process %d"
-                           " (%s): task_session(p)==tty->session\n",
-                           task_pid_nr(p), p->comm);
-                       send_sig(SIGKILL, p, 1);
-                       continue;
-               }
-               task_lock(p);
-               if (p->files) {
-                       /*
-                        * We don't take a ref to the file, so we must
-                        * hold ->file_lock instead.
-                        */
-                       spin_lock(&p->files->file_lock);
-                       fdt = files_fdtable(p->files);
-                       for (i = 0; i < fdt->max_fds; i++) {
-                               filp = fcheck_files(p->files, i);
-                               if (!filp)
-                                       continue;
-                               if (filp->f_op->read == tty_read &&
-                                   file_tty(filp) == tty) {
-                                       printk(KERN_NOTICE "SAK: killed process %d"
-                                           " (%s): fd#%d opened to the tty\n",
-                                           task_pid_nr(p), p->comm, i);
-                                       force_sig(SIGKILL, p);
-                                       break;
-                               }
-                       }
-                       spin_unlock(&p->files->file_lock);
-               }
-               task_unlock(p);
-       } while_each_thread(g, p);
-       read_unlock(&tasklist_lock);
-#endif
-}
-
-static void do_SAK_work(struct work_struct *work)
-{
-       struct tty_struct *tty =
-               container_of(work, struct tty_struct, SAK_work);
-       __do_SAK(tty);
-}
-
-/*
- * The tq handling here is a little racy - tty->SAK_work may already be queued.
- * Fortunately we don't need to worry, because if ->SAK_work is already queued,
- * the values which we write to it will be identical to the values which it
- * already has. --akpm
- */
-void do_SAK(struct tty_struct *tty)
-{
-       if (!tty)
-               return;
-       schedule_work(&tty->SAK_work);
-}
-
-EXPORT_SYMBOL(do_SAK);
-
-static int dev_match_devt(struct device *dev, void *data)
-{
-       dev_t *devt = data;
-       return dev->devt == *devt;
-}
-
-/* Must put_device() after it's unused! */
-static struct device *tty_get_device(struct tty_struct *tty)
-{
-       dev_t devt = tty_devnum(tty);
-       return class_find_device(tty_class, NULL, &devt, dev_match_devt);
-}
-
-
-/**
- *     initialize_tty_struct
- *     @tty: tty to initialize
- *
- *     This subroutine initializes a tty structure that has been newly
- *     allocated.
- *
- *     Locking: none - tty in question must not be exposed at this point
- */
-
-void initialize_tty_struct(struct tty_struct *tty,
-               struct tty_driver *driver, int idx)
-{
-       memset(tty, 0, sizeof(struct tty_struct));
-       kref_init(&tty->kref);
-       tty->magic = TTY_MAGIC;
-       tty_ldisc_init(tty);
-       tty->session = NULL;
-       tty->pgrp = NULL;
-       tty->overrun_time = jiffies;
-       tty->buf.head = tty->buf.tail = NULL;
-       tty_buffer_init(tty);
-       mutex_init(&tty->termios_mutex);
-       mutex_init(&tty->ldisc_mutex);
-       init_waitqueue_head(&tty->write_wait);
-       init_waitqueue_head(&tty->read_wait);
-       INIT_WORK(&tty->hangup_work, do_tty_hangup);
-       mutex_init(&tty->atomic_read_lock);
-       mutex_init(&tty->atomic_write_lock);
-       mutex_init(&tty->output_lock);
-       mutex_init(&tty->echo_lock);
-       spin_lock_init(&tty->read_lock);
-       spin_lock_init(&tty->ctrl_lock);
-       INIT_LIST_HEAD(&tty->tty_files);
-       INIT_WORK(&tty->SAK_work, do_SAK_work);
-
-       tty->driver = driver;
-       tty->ops = driver->ops;
-       tty->index = idx;
-       tty_line_name(driver, idx, tty->name);
-       tty->dev = tty_get_device(tty);
-}
-
-/**
- *     tty_put_char    -       write one character to a tty
- *     @tty: tty
- *     @ch: character
- *
- *     Write one byte to the tty using the provided put_char method
- *     if present. Returns the number of characters successfully output.
- *
- *     Note: the specific put_char operation in the driver layer may go
- *     away soon. Don't call it directly, use this method
- */
-
-int tty_put_char(struct tty_struct *tty, unsigned char ch)
-{
-       if (tty->ops->put_char)
-               return tty->ops->put_char(tty, ch);
-       return tty->ops->write(tty, &ch, 1);
-}
-EXPORT_SYMBOL_GPL(tty_put_char);
-
-struct class *tty_class;
-
-/**
- *     tty_register_device - register a tty device
- *     @driver: the tty driver that describes the tty device
- *     @index: the index in the tty driver for this tty device
- *     @device: a struct device that is associated with this tty device.
- *             This field is optional, if there is no known struct device
- *             for this tty device it can be set to NULL safely.
- *
- *     Returns a pointer to the struct device for this tty device
- *     (or ERR_PTR(-EFOO) on error).
- *
- *     This call is required to be made to register an individual tty device
- *     if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set.  If
- *     that bit is not set, this function should not be called by a tty
- *     driver.
- *
- *     Locking: ??
- */
-
-struct device *tty_register_device(struct tty_driver *driver, unsigned index,
-                                  struct device *device)
-{
-       char name[64];
-       dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
-
-       if (index >= driver->num) {
-               printk(KERN_ERR "Attempt to register invalid tty line number "
-                      " (%d).\n", index);
-               return ERR_PTR(-EINVAL);
-       }
-
-       if (driver->type == TTY_DRIVER_TYPE_PTY)
-               pty_line_name(driver, index, name);
-       else
-               tty_line_name(driver, index, name);
-
-       return device_create(tty_class, device, dev, NULL, name);
-}
-EXPORT_SYMBOL(tty_register_device);
-
-/**
- *     tty_unregister_device - unregister a tty device
- *     @driver: the tty driver that describes the tty device
- *     @index: the index in the tty driver for this tty device
- *
- *     If a tty device is registered with a call to tty_register_device() then
- *     this function must be called when the tty device is gone.
- *
- *     Locking: ??
- */
-
-void tty_unregister_device(struct tty_driver *driver, unsigned index)
-{
-       device_destroy(tty_class,
-               MKDEV(driver->major, driver->minor_start) + index);
-}
-EXPORT_SYMBOL(tty_unregister_device);
-
-struct tty_driver *alloc_tty_driver(int lines)
-{
-       struct tty_driver *driver;
-
-       driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
-       if (driver) {
-               kref_init(&driver->kref);
-               driver->magic = TTY_DRIVER_MAGIC;
-               driver->num = lines;
-               /* later we'll move allocation of tables here */
-       }
-       return driver;
-}
-EXPORT_SYMBOL(alloc_tty_driver);
-
-static void destruct_tty_driver(struct kref *kref)
-{
-       struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
-       int i;
-       struct ktermios *tp;
-       void *p;
-
-       if (driver->flags & TTY_DRIVER_INSTALLED) {
-               /*
-                * Free the termios and termios_locked structures because
-                * we don't want to get memory leaks when modular tty
-                * drivers are removed from the kernel.
-                */
-               for (i = 0; i < driver->num; i++) {
-                       tp = driver->termios[i];
-                       if (tp) {
-                               driver->termios[i] = NULL;
-                               kfree(tp);
-                       }
-                       if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
-                               tty_unregister_device(driver, i);
-               }
-               p = driver->ttys;
-               proc_tty_unregister_driver(driver);
-               driver->ttys = NULL;
-               driver->termios = NULL;
-               kfree(p);
-               cdev_del(&driver->cdev);
-       }
-       kfree(driver);
-}
-
-void tty_driver_kref_put(struct tty_driver *driver)
-{
-       kref_put(&driver->kref, destruct_tty_driver);
-}
-EXPORT_SYMBOL(tty_driver_kref_put);
-
-void tty_set_operations(struct tty_driver *driver,
-                       const struct tty_operations *op)
-{
-       driver->ops = op;
-};
-EXPORT_SYMBOL(tty_set_operations);
-
-void put_tty_driver(struct tty_driver *d)
-{
-       tty_driver_kref_put(d);
-}
-EXPORT_SYMBOL(put_tty_driver);
-
-/*
- * Called by a tty driver to register itself.
- */
-int tty_register_driver(struct tty_driver *driver)
-{
-       int error;
-       int i;
-       dev_t dev;
-       void **p = NULL;
-       struct device *d;
-
-       if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
-               p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
-               if (!p)
-                       return -ENOMEM;
-       }
-
-       if (!driver->major) {
-               error = alloc_chrdev_region(&dev, driver->minor_start,
-                                               driver->num, driver->name);
-               if (!error) {
-                       driver->major = MAJOR(dev);
-                       driver->minor_start = MINOR(dev);
-               }
-       } else {
-               dev = MKDEV(driver->major, driver->minor_start);
-               error = register_chrdev_region(dev, driver->num, driver->name);
-       }
-       if (error < 0) {
-               kfree(p);
-               return error;
-       }
-
-       if (p) {
-               driver->ttys = (struct tty_struct **)p;
-               driver->termios = (struct ktermios **)(p + driver->num);
-       } else {
-               driver->ttys = NULL;
-               driver->termios = NULL;
-       }
-
-       cdev_init(&driver->cdev, &tty_fops);
-       driver->cdev.owner = driver->owner;
-       error = cdev_add(&driver->cdev, dev, driver->num);
-       if (error) {
-               unregister_chrdev_region(dev, driver->num);
-               driver->ttys = NULL;
-               driver->termios = NULL;
-               kfree(p);
-               return error;
-       }
-
-       mutex_lock(&tty_mutex);
-       list_add(&driver->tty_drivers, &tty_drivers);
-       mutex_unlock(&tty_mutex);
-
-       if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
-               for (i = 0; i < driver->num; i++) {
-                       d = tty_register_device(driver, i, NULL);
-                       if (IS_ERR(d)) {
-                               error = PTR_ERR(d);
-                               goto err;
-                       }
-               }
-       }
-       proc_tty_register_driver(driver);
-       driver->flags |= TTY_DRIVER_INSTALLED;
-       return 0;
-
-err:
-       for (i--; i >= 0; i--)
-               tty_unregister_device(driver, i);
-
-       mutex_lock(&tty_mutex);
-       list_del(&driver->tty_drivers);
-       mutex_unlock(&tty_mutex);
-
-       unregister_chrdev_region(dev, driver->num);
-       driver->ttys = NULL;
-       driver->termios = NULL;
-       kfree(p);
-       return error;
-}
-
-EXPORT_SYMBOL(tty_register_driver);
-
-/*
- * Called by a tty driver to unregister itself.
- */
-int tty_unregister_driver(struct tty_driver *driver)
-{
-#if 0
-       /* FIXME */
-       if (driver->refcount)
-               return -EBUSY;
-#endif
-       unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
-                               driver->num);
-       mutex_lock(&tty_mutex);
-       list_del(&driver->tty_drivers);
-       mutex_unlock(&tty_mutex);
-       return 0;
-}
-
-EXPORT_SYMBOL(tty_unregister_driver);
-
-dev_t tty_devnum(struct tty_struct *tty)
-{
-       return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
-}
-EXPORT_SYMBOL(tty_devnum);
-
-void proc_clear_tty(struct task_struct *p)
-{
-       unsigned long flags;
-       struct tty_struct *tty;
-       spin_lock_irqsave(&p->sighand->siglock, flags);
-       tty = p->signal->tty;
-       p->signal->tty = NULL;
-       spin_unlock_irqrestore(&p->sighand->siglock, flags);
-       tty_kref_put(tty);
-}
-
-/* Called under the sighand lock */
-
-static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
-{
-       if (tty) {
-               unsigned long flags;
-               /* We should not have a session or pgrp to put here but.... */
-               spin_lock_irqsave(&tty->ctrl_lock, flags);
-               put_pid(tty->session);
-               put_pid(tty->pgrp);
-               tty->pgrp = get_pid(task_pgrp(tsk));
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               tty->session = get_pid(task_session(tsk));
-               if (tsk->signal->tty) {
-                       printk(KERN_DEBUG "tty not NULL!!\n");
-                       tty_kref_put(tsk->signal->tty);
-               }
-       }
-       put_pid(tsk->signal->tty_old_pgrp);
-       tsk->signal->tty = tty_kref_get(tty);
-       tsk->signal->tty_old_pgrp = NULL;
-}
-
-static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
-{
-       spin_lock_irq(&tsk->sighand->siglock);
-       __proc_set_tty(tsk, tty);
-       spin_unlock_irq(&tsk->sighand->siglock);
-}
-
-struct tty_struct *get_current_tty(void)
-{
-       struct tty_struct *tty;
-       unsigned long flags;
-
-       spin_lock_irqsave(&current->sighand->siglock, flags);
-       tty = tty_kref_get(current->signal->tty);
-       spin_unlock_irqrestore(&current->sighand->siglock, flags);
-       return tty;
-}
-EXPORT_SYMBOL_GPL(get_current_tty);
-
-void tty_default_fops(struct file_operations *fops)
-{
-       *fops = tty_fops;
-}
-
-/*
- * Initialize the console device. This is called *early*, so
- * we can't necessarily depend on lots of kernel help here.
- * Just do some early initializations, and do the complex setup
- * later.
- */
-void __init console_init(void)
-{
-       initcall_t *call;
-
-       /* Setup the default TTY line discipline. */
-       tty_ldisc_begin();
-
-       /*
-        * set up the console device so that later boot sequences can
-        * inform about problems etc..
-        */
-       call = __con_initcall_start;
-       while (call < __con_initcall_end) {
-               (*call)();
-               call++;
-       }
-}
-
-static char *tty_devnode(struct device *dev, mode_t *mode)
-{
-       if (!mode)
-               return NULL;
-       if (dev->devt == MKDEV(TTYAUX_MAJOR, 0) ||
-           dev->devt == MKDEV(TTYAUX_MAJOR, 2))
-               *mode = 0666;
-       return NULL;
-}
-
-static int __init tty_class_init(void)
-{
-       tty_class = class_create(THIS_MODULE, "tty");
-       if (IS_ERR(tty_class))
-               return PTR_ERR(tty_class);
-       tty_class->devnode = tty_devnode;
-       return 0;
-}
-
-postcore_initcall(tty_class_init);
-
-/* 3/2004 jmc: why do these devices exist? */
-
-static struct cdev tty_cdev, console_cdev;
-
-/*
- * Ok, now we can initialize the rest of the tty devices and can count
- * on memory allocations, interrupts etc..
- */
-int __init tty_init(void)
-{
-       cdev_init(&tty_cdev, &tty_fops);
-       if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
-           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
-               panic("Couldn't register /dev/tty driver\n");
-       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
-                             "tty");
-
-       cdev_init(&console_cdev, &console_fops);
-       if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
-           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
-               panic("Couldn't register /dev/console driver\n");
-       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
-                             "console");
-
-#ifdef CONFIG_VT
-       vty_init(&console_fops);
-#endif
-       return 0;
-}
-
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
deleted file mode 100644 (file)
index 0c18899..0000000
+++ /dev/null
@@ -1,1179 +0,0 @@
-/*
- *  linux/drivers/char/tty_ioctl.c
- *
- *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *
- * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
- * which can be dynamically activated and de-activated by the line
- * discipline handling modules (like SLIP).
- */
-
-#include <linux/types.h>
-#include <linux/termios.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/tty.h>
-#include <linux/fcntl.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/bitops.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#undef TTY_DEBUG_WAIT_UNTIL_SENT
-
-#undef DEBUG
-
-/*
- * Internal flag options for termios setting behavior
- */
-#define TERMIOS_FLUSH  1
-#define TERMIOS_WAIT   2
-#define TERMIOS_TERMIO 4
-#define TERMIOS_OLD    8
-
-
-/**
- *     tty_chars_in_buffer     -       characters pending
- *     @tty: terminal
- *
- *     Return the number of bytes of data in the device private
- *     output queue. If no private method is supplied there is assumed
- *     to be no queue on the device.
- */
-
-int tty_chars_in_buffer(struct tty_struct *tty)
-{
-       if (tty->ops->chars_in_buffer)
-               return tty->ops->chars_in_buffer(tty);
-       else
-               return 0;
-}
-EXPORT_SYMBOL(tty_chars_in_buffer);
-
-/**
- *     tty_write_room          -       write queue space
- *     @tty: terminal
- *
- *     Return the number of bytes that can be queued to this device
- *     at the present time. The result should be treated as a guarantee
- *     and the driver cannot offer a value it later shrinks by more than
- *     the number of bytes written. If no method is provided 2K is always
- *     returned and data may be lost as there will be no flow control.
- */
-int tty_write_room(struct tty_struct *tty)
-{
-       if (tty->ops->write_room)
-               return tty->ops->write_room(tty);
-       return 2048;
-}
-EXPORT_SYMBOL(tty_write_room);
-
-/**
- *     tty_driver_flush_buffer -       discard internal buffer
- *     @tty: terminal
- *
- *     Discard the internal output buffer for this device. If no method
- *     is provided then either the buffer cannot be hardware flushed or
- *     there is no buffer driver side.
- */
-void tty_driver_flush_buffer(struct tty_struct *tty)
-{
-       if (tty->ops->flush_buffer)
-               tty->ops->flush_buffer(tty);
-}
-EXPORT_SYMBOL(tty_driver_flush_buffer);
-
-/**
- *     tty_throttle            -       flow control
- *     @tty: terminal
- *
- *     Indicate that a tty should stop transmitting data down the stack.
- *     Takes the termios mutex to protect against parallel throttle/unthrottle
- *     and also to ensure the driver can consistently reference its own
- *     termios data at this point when implementing software flow control.
- */
-
-void tty_throttle(struct tty_struct *tty)
-{
-       mutex_lock(&tty->termios_mutex);
-       /* check TTY_THROTTLED first so it indicates our state */
-       if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
-           tty->ops->throttle)
-               tty->ops->throttle(tty);
-       mutex_unlock(&tty->termios_mutex);
-}
-EXPORT_SYMBOL(tty_throttle);
-
-/**
- *     tty_unthrottle          -       flow control
- *     @tty: terminal
- *
- *     Indicate that a tty may continue transmitting data down the stack.
- *     Takes the termios mutex to protect against parallel throttle/unthrottle
- *     and also to ensure the driver can consistently reference its own
- *     termios data at this point when implementing software flow control.
- *
- *     Drivers should however remember that the stack can issue a throttle,
- *     then change flow control method, then unthrottle.
- */
-
-void tty_unthrottle(struct tty_struct *tty)
-{
-       mutex_lock(&tty->termios_mutex);
-       if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
-           tty->ops->unthrottle)
-               tty->ops->unthrottle(tty);
-       mutex_unlock(&tty->termios_mutex);
-}
-EXPORT_SYMBOL(tty_unthrottle);
-
-/**
- *     tty_wait_until_sent     -       wait for I/O to finish
- *     @tty: tty we are waiting for
- *     @timeout: how long we will wait
- *
- *     Wait for characters pending in a tty driver to hit the wire, or
- *     for a timeout to occur (eg due to flow control)
- *
- *     Locking: none
- */
-
-void tty_wait_until_sent(struct tty_struct *tty, long timeout)
-{
-#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
-       char buf[64];
-
-       printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
-#endif
-       if (!timeout)
-               timeout = MAX_SCHEDULE_TIMEOUT;
-       if (wait_event_interruptible_timeout(tty->write_wait,
-                       !tty_chars_in_buffer(tty), timeout) >= 0) {
-               if (tty->ops->wait_until_sent)
-                       tty->ops->wait_until_sent(tty, timeout);
-       }
-}
-EXPORT_SYMBOL(tty_wait_until_sent);
-
-
-/*
- *             Termios Helper Methods
- */
-
-static void unset_locked_termios(struct ktermios *termios,
-                                struct ktermios *old,
-                                struct ktermios *locked)
-{
-       int     i;
-
-#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
-
-       if (!locked) {
-               printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
-               return;
-       }
-
-       NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
-       NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
-       NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
-       NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
-       termios->c_line = locked->c_line ? old->c_line : termios->c_line;
-       for (i = 0; i < NCCS; i++)
-               termios->c_cc[i] = locked->c_cc[i] ?
-                       old->c_cc[i] : termios->c_cc[i];
-       /* FIXME: What should we do for i/ospeed */
-}
-
-/*
- * Routine which returns the baud rate of the tty
- *
- * Note that the baud_table needs to be kept in sync with the
- * include/asm/termbits.h file.
- */
-static const speed_t baud_table[] = {
-       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-       9600, 19200, 38400, 57600, 115200, 230400, 460800,
-#ifdef __sparc__
-       76800, 153600, 307200, 614400, 921600
-#else
-       500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
-       2500000, 3000000, 3500000, 4000000
-#endif
-};
-
-#ifndef __sparc__
-static const tcflag_t baud_bits[] = {
-       B0, B50, B75, B110, B134, B150, B200, B300, B600,
-       B1200, B1800, B2400, B4800, B9600, B19200, B38400,
-       B57600, B115200, B230400, B460800, B500000, B576000,
-       B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
-       B3000000, B3500000, B4000000
-};
-#else
-static const tcflag_t baud_bits[] = {
-       B0, B50, B75, B110, B134, B150, B200, B300, B600,
-       B1200, B1800, B2400, B4800, B9600, B19200, B38400,
-       B57600, B115200, B230400, B460800, B76800, B153600,
-       B307200, B614400, B921600
-};
-#endif
-
-static int n_baud_table = ARRAY_SIZE(baud_table);
-
-/**
- *     tty_termios_baud_rate
- *     @termios: termios structure
- *
- *     Convert termios baud rate data into a speed. This should be called
- *     with the termios lock held if this termios is a terminal termios
- *     structure. May change the termios data. Device drivers can call this
- *     function but should use ->c_[io]speed directly as they are updated.
- *
- *     Locking: none
- */
-
-speed_t tty_termios_baud_rate(struct ktermios *termios)
-{
-       unsigned int cbaud;
-
-       cbaud = termios->c_cflag & CBAUD;
-
-#ifdef BOTHER
-       /* Magic token for arbitary speed via c_ispeed/c_ospeed */
-       if (cbaud == BOTHER)
-               return termios->c_ospeed;
-#endif
-       if (cbaud & CBAUDEX) {
-               cbaud &= ~CBAUDEX;
-
-               if (cbaud < 1 || cbaud + 15 > n_baud_table)
-                       termios->c_cflag &= ~CBAUDEX;
-               else
-                       cbaud += 15;
-       }
-       return baud_table[cbaud];
-}
-EXPORT_SYMBOL(tty_termios_baud_rate);
-
-/**
- *     tty_termios_input_baud_rate
- *     @termios: termios structure
- *
- *     Convert termios baud rate data into a speed. This should be called
- *     with the termios lock held if this termios is a terminal termios
- *     structure. May change the termios data. Device drivers can call this
- *     function but should use ->c_[io]speed directly as they are updated.
- *
- *     Locking: none
- */
-
-speed_t tty_termios_input_baud_rate(struct ktermios *termios)
-{
-#ifdef IBSHIFT
-       unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
-
-       if (cbaud == B0)
-               return tty_termios_baud_rate(termios);
-
-       /* Magic token for arbitary speed via c_ispeed*/
-       if (cbaud == BOTHER)
-               return termios->c_ispeed;
-
-       if (cbaud & CBAUDEX) {
-               cbaud &= ~CBAUDEX;
-
-               if (cbaud < 1 || cbaud + 15 > n_baud_table)
-                       termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
-               else
-                       cbaud += 15;
-       }
-       return baud_table[cbaud];
-#else
-       return tty_termios_baud_rate(termios);
-#endif
-}
-EXPORT_SYMBOL(tty_termios_input_baud_rate);
-
-/**
- *     tty_termios_encode_baud_rate
- *     @termios: ktermios structure holding user requested state
- *     @ispeed: input speed
- *     @ospeed: output speed
- *
- *     Encode the speeds set into the passed termios structure. This is
- *     used as a library helper for drivers os that they can report back
- *     the actual speed selected when it differs from the speed requested
- *
- *     For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
- *     we need to carefully set the bits when the user does not get the
- *     desired speed. We allow small margins and preserve as much of possible
- *     of the input intent to keep compatibility.
- *
- *     Locking: Caller should hold termios lock. This is already held
- *     when calling this function from the driver termios handler.
- *
- *     The ifdefs deal with platforms whose owners have yet to update them
- *     and will all go away once this is done.
- */
-
-void tty_termios_encode_baud_rate(struct ktermios *termios,
-                                 speed_t ibaud, speed_t obaud)
-{
-       int i = 0;
-       int ifound = -1, ofound = -1;
-       int iclose = ibaud/50, oclose = obaud/50;
-       int ibinput = 0;
-
-       if (obaud == 0)                 /* CD dropped             */
-               ibaud = 0;              /* Clear ibaud to be sure */
-
-       termios->c_ispeed = ibaud;
-       termios->c_ospeed = obaud;
-
-#ifdef BOTHER
-       /* If the user asked for a precise weird speed give a precise weird
-          answer. If they asked for a Bfoo speed they many have problems
-          digesting non-exact replies so fuzz a bit */
-
-       if ((termios->c_cflag & CBAUD) == BOTHER)
-               oclose = 0;
-       if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
-               iclose = 0;
-       if ((termios->c_cflag >> IBSHIFT) & CBAUD)
-               ibinput = 1;    /* An input speed was specified */
-#endif
-       termios->c_cflag &= ~CBAUD;
-
-       /*
-        *      Our goal is to find a close match to the standard baud rate
-        *      returned. Walk the baud rate table and if we get a very close
-        *      match then report back the speed as a POSIX Bxxxx value by
-        *      preference
-        */
-
-       do {
-               if (obaud - oclose <= baud_table[i] &&
-                   obaud + oclose >= baud_table[i]) {
-                       termios->c_cflag |= baud_bits[i];
-                       ofound = i;
-               }
-               if (ibaud - iclose <= baud_table[i] &&
-                   ibaud + iclose >= baud_table[i]) {
-                       /* For the case input == output don't set IBAUD bits
-                          if the user didn't do so */
-                       if (ofound == i && !ibinput)
-                               ifound  = i;
-#ifdef IBSHIFT
-                       else {
-                               ifound = i;
-                               termios->c_cflag |= (baud_bits[i] << IBSHIFT);
-                       }
-#endif
-               }
-       } while (++i < n_baud_table);
-
-       /*
-        *      If we found no match then use BOTHER if provided or warn
-        *      the user their platform maintainer needs to wake up if not.
-        */
-#ifdef BOTHER
-       if (ofound == -1)
-               termios->c_cflag |= BOTHER;
-       /* Set exact input bits only if the input and output differ or the
-          user already did */
-       if (ifound == -1 && (ibaud != obaud || ibinput))
-               termios->c_cflag |= (BOTHER << IBSHIFT);
-#else
-       if (ifound == -1 || ofound == -1) {
-               printk_once(KERN_WARNING "tty: Unable to return correct "
-                         "speed data as your architecture needs updating.\n");
-       }
-#endif
-}
-EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
-
-/**
- *     tty_encode_baud_rate            -       set baud rate of the tty
- *     @ibaud: input baud rate
- *     @obad: output baud rate
- *
- *     Update the current termios data for the tty with the new speed
- *     settings. The caller must hold the termios_mutex for the tty in
- *     question.
- */
-
-void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
-{
-       tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
-}
-EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
-
-/**
- *     tty_get_baud_rate       -       get tty bit rates
- *     @tty: tty to query
- *
- *     Returns the baud rate as an integer for this terminal. The
- *     termios lock must be held by the caller and the terminal bit
- *     flags may be updated.
- *
- *     Locking: none
- */
-
-speed_t tty_get_baud_rate(struct tty_struct *tty)
-{
-       speed_t baud = tty_termios_baud_rate(tty->termios);
-
-       if (baud == 38400 && tty->alt_speed) {
-               if (!tty->warned) {
-                       printk(KERN_WARNING "Use of setserial/setrocket to "
-                                           "set SPD_* flags is deprecated\n");
-                       tty->warned = 1;
-               }
-               baud = tty->alt_speed;
-       }
-
-       return baud;
-}
-EXPORT_SYMBOL(tty_get_baud_rate);
-
-/**
- *     tty_termios_copy_hw     -       copy hardware settings
- *     @new: New termios
- *     @old: Old termios
- *
- *     Propogate the hardware specific terminal setting bits from
- *     the old termios structure to the new one. This is used in cases
- *     where the hardware does not support reconfiguration or as a helper
- *     in some cases where only minimal reconfiguration is supported
- */
-
-void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
-{
-       /* The bits a dumb device handles in software. Smart devices need
-          to always provide a set_termios method */
-       new->c_cflag &= HUPCL | CREAD | CLOCAL;
-       new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
-       new->c_ispeed = old->c_ispeed;
-       new->c_ospeed = old->c_ospeed;
-}
-EXPORT_SYMBOL(tty_termios_copy_hw);
-
-/**
- *     tty_termios_hw_change   -       check for setting change
- *     @a: termios
- *     @b: termios to compare
- *
- *     Check if any of the bits that affect a dumb device have changed
- *     between the two termios structures, or a speed change is needed.
- */
-
-int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
-{
-       if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
-               return 1;
-       if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
-               return 1;
-       return 0;
-}
-EXPORT_SYMBOL(tty_termios_hw_change);
-
-/**
- *     change_termios          -       update termios values
- *     @tty: tty to update
- *     @new_termios: desired new value
- *
- *     Perform updates to the termios values set on this terminal. There
- *     is a bit of layering violation here with n_tty in terms of the
- *     internal knowledge of this function.
- *
- *     Locking: termios_mutex
- */
-
-static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
-{
-       struct ktermios old_termios;
-       struct tty_ldisc *ld;
-       unsigned long flags;
-
-       /*
-        *      Perform the actual termios internal changes under lock.
-        */
-
-
-       /* FIXME: we need to decide on some locking/ordering semantics
-          for the set_termios notification eventually */
-       mutex_lock(&tty->termios_mutex);
-       old_termios = *tty->termios;
-       *tty->termios = *new_termios;
-       unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
-
-       /* See if packet mode change of state. */
-       if (tty->link && tty->link->packet) {
-               int extproc = (old_termios.c_lflag & EXTPROC) |
-                               (tty->termios->c_lflag & EXTPROC);
-               int old_flow = ((old_termios.c_iflag & IXON) &&
-                               (old_termios.c_cc[VSTOP] == '\023') &&
-                               (old_termios.c_cc[VSTART] == '\021'));
-               int new_flow = (I_IXON(tty) &&
-                               STOP_CHAR(tty) == '\023' &&
-                               START_CHAR(tty) == '\021');
-               if ((old_flow != new_flow) || extproc) {
-                       spin_lock_irqsave(&tty->ctrl_lock, flags);
-                       if (old_flow != new_flow) {
-                               tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
-                               if (new_flow)
-                                       tty->ctrl_status |= TIOCPKT_DOSTOP;
-                               else
-                                       tty->ctrl_status |= TIOCPKT_NOSTOP;
-                       }
-                       if (extproc)
-                               tty->ctrl_status |= TIOCPKT_IOCTL;
-                       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-                       wake_up_interruptible(&tty->link->read_wait);
-               }
-       }
-
-       if (tty->ops->set_termios)
-               (*tty->ops->set_termios)(tty, &old_termios);
-       else
-               tty_termios_copy_hw(tty->termios, &old_termios);
-
-       ld = tty_ldisc_ref(tty);
-       if (ld != NULL) {
-               if (ld->ops->set_termios)
-                       (ld->ops->set_termios)(tty, &old_termios);
-               tty_ldisc_deref(ld);
-       }
-       mutex_unlock(&tty->termios_mutex);
-}
-
-/**
- *     set_termios             -       set termios values for a tty
- *     @tty: terminal device
- *     @arg: user data
- *     @opt: option information
- *
- *     Helper function to prepare termios data and run necessary other
- *     functions before using change_termios to do the actual changes.
- *
- *     Locking:
- *             Called functions take ldisc and termios_mutex locks
- */
-
-static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
-{
-       struct ktermios tmp_termios;
-       struct tty_ldisc *ld;
-       int retval = tty_check_change(tty);
-
-       if (retval)
-               return retval;
-
-       mutex_lock(&tty->termios_mutex);
-       memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
-       mutex_unlock(&tty->termios_mutex);
-
-       if (opt & TERMIOS_TERMIO) {
-               if (user_termio_to_kernel_termios(&tmp_termios,
-                                               (struct termio __user *)arg))
-                       return -EFAULT;
-#ifdef TCGETS2
-       } else if (opt & TERMIOS_OLD) {
-               if (user_termios_to_kernel_termios_1(&tmp_termios,
-                                               (struct termios __user *)arg))
-                       return -EFAULT;
-       } else {
-               if (user_termios_to_kernel_termios(&tmp_termios,
-                                               (struct termios2 __user *)arg))
-                       return -EFAULT;
-       }
-#else
-       } else if (user_termios_to_kernel_termios(&tmp_termios,
-                                       (struct termios __user *)arg))
-               return -EFAULT;
-#endif
-
-       /* If old style Bfoo values are used then load c_ispeed/c_ospeed
-        * with the real speed so its unconditionally usable */
-       tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
-       tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
-
-       ld = tty_ldisc_ref(tty);
-
-       if (ld != NULL) {
-               if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               tty_ldisc_deref(ld);
-       }
-
-       if (opt & TERMIOS_WAIT) {
-               tty_wait_until_sent(tty, 0);
-               if (signal_pending(current))
-                       return -EINTR;
-       }
-
-       change_termios(tty, &tmp_termios);
-
-       /* FIXME: Arguably if tmp_termios == tty->termios AND the
-          actual requested termios was not tmp_termios then we may
-          want to return an error as no user requested change has
-          succeeded */
-       return 0;
-}
-
-static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
-{
-       mutex_lock(&tty->termios_mutex);
-       memcpy(kterm, tty->termios, sizeof(struct ktermios));
-       mutex_unlock(&tty->termios_mutex);
-}
-
-static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
-{
-       mutex_lock(&tty->termios_mutex);
-       memcpy(kterm, tty->termios_locked, sizeof(struct ktermios));
-       mutex_unlock(&tty->termios_mutex);
-}
-
-static int get_termio(struct tty_struct *tty, struct termio __user *termio)
-{
-       struct ktermios kterm;
-       copy_termios(tty, &kterm);
-       if (kernel_termios_to_user_termio(termio, &kterm))
-               return -EFAULT;
-       return 0;
-}
-
-
-#ifdef TCGETX
-
-/**
- *     set_termiox     -       set termiox fields if possible
- *     @tty: terminal
- *     @arg: termiox structure from user
- *     @opt: option flags for ioctl type
- *
- *     Implement the device calling points for the SYS5 termiox ioctl
- *     interface in Linux
- */
-
-static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
-{
-       struct termiox tnew;
-       struct tty_ldisc *ld;
-
-       if (tty->termiox == NULL)
-               return -EINVAL;
-       if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
-               return -EFAULT;
-
-       ld = tty_ldisc_ref(tty);
-       if (ld != NULL) {
-               if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               tty_ldisc_deref(ld);
-       }
-       if (opt & TERMIOS_WAIT) {
-               tty_wait_until_sent(tty, 0);
-               if (signal_pending(current))
-                       return -EINTR;
-       }
-
-       mutex_lock(&tty->termios_mutex);
-       if (tty->ops->set_termiox)
-               tty->ops->set_termiox(tty, &tnew);
-       mutex_unlock(&tty->termios_mutex);
-       return 0;
-}
-
-#endif
-
-
-#ifdef TIOCGETP
-/*
- * These are deprecated, but there is limited support..
- *
- * The "sg_flags" translation is a joke..
- */
-static int get_sgflags(struct tty_struct *tty)
-{
-       int flags = 0;
-
-       if (!(tty->termios->c_lflag & ICANON)) {
-               if (tty->termios->c_lflag & ISIG)
-                       flags |= 0x02;          /* cbreak */
-               else
-                       flags |= 0x20;          /* raw */
-       }
-       if (tty->termios->c_lflag & ECHO)
-               flags |= 0x08;                  /* echo */
-       if (tty->termios->c_oflag & OPOST)
-               if (tty->termios->c_oflag & ONLCR)
-                       flags |= 0x10;          /* crmod */
-       return flags;
-}
-
-static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
-{
-       struct sgttyb tmp;
-
-       mutex_lock(&tty->termios_mutex);
-       tmp.sg_ispeed = tty->termios->c_ispeed;
-       tmp.sg_ospeed = tty->termios->c_ospeed;
-       tmp.sg_erase = tty->termios->c_cc[VERASE];
-       tmp.sg_kill = tty->termios->c_cc[VKILL];
-       tmp.sg_flags = get_sgflags(tty);
-       mutex_unlock(&tty->termios_mutex);
-
-       return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
-}
-
-static void set_sgflags(struct ktermios *termios, int flags)
-{
-       termios->c_iflag = ICRNL | IXON;
-       termios->c_oflag = 0;
-       termios->c_lflag = ISIG | ICANON;
-       if (flags & 0x02) {     /* cbreak */
-               termios->c_iflag = 0;
-               termios->c_lflag &= ~ICANON;
-       }
-       if (flags & 0x08) {             /* echo */
-               termios->c_lflag |= ECHO | ECHOE | ECHOK |
-                                   ECHOCTL | ECHOKE | IEXTEN;
-       }
-       if (flags & 0x10) {             /* crmod */
-               termios->c_oflag |= OPOST | ONLCR;
-       }
-       if (flags & 0x20) {     /* raw */
-               termios->c_iflag = 0;
-               termios->c_lflag &= ~(ISIG | ICANON);
-       }
-       if (!(termios->c_lflag & ICANON)) {
-               termios->c_cc[VMIN] = 1;
-               termios->c_cc[VTIME] = 0;
-       }
-}
-
-/**
- *     set_sgttyb              -       set legacy terminal values
- *     @tty: tty structure
- *     @sgttyb: pointer to old style terminal structure
- *
- *     Updates a terminal from the legacy BSD style terminal information
- *     structure.
- *
- *     Locking: termios_mutex
- */
-
-static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
-{
-       int retval;
-       struct sgttyb tmp;
-       struct ktermios termios;
-
-       retval = tty_check_change(tty);
-       if (retval)
-               return retval;
-
-       if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
-               return -EFAULT;
-
-       mutex_lock(&tty->termios_mutex);
-       termios = *tty->termios;
-       termios.c_cc[VERASE] = tmp.sg_erase;
-       termios.c_cc[VKILL] = tmp.sg_kill;
-       set_sgflags(&termios, tmp.sg_flags);
-       /* Try and encode into Bfoo format */
-#ifdef BOTHER
-       tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
-                                               termios.c_ospeed);
-#endif
-       mutex_unlock(&tty->termios_mutex);
-       change_termios(tty, &termios);
-       return 0;
-}
-#endif
-
-#ifdef TIOCGETC
-static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
-{
-       struct tchars tmp;
-
-       mutex_lock(&tty->termios_mutex);
-       tmp.t_intrc = tty->termios->c_cc[VINTR];
-       tmp.t_quitc = tty->termios->c_cc[VQUIT];
-       tmp.t_startc = tty->termios->c_cc[VSTART];
-       tmp.t_stopc = tty->termios->c_cc[VSTOP];
-       tmp.t_eofc = tty->termios->c_cc[VEOF];
-       tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
-       mutex_unlock(&tty->termios_mutex);
-       return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
-}
-
-static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
-{
-       struct tchars tmp;
-
-       if (copy_from_user(&tmp, tchars, sizeof(tmp)))
-               return -EFAULT;
-       mutex_lock(&tty->termios_mutex);
-       tty->termios->c_cc[VINTR] = tmp.t_intrc;
-       tty->termios->c_cc[VQUIT] = tmp.t_quitc;
-       tty->termios->c_cc[VSTART] = tmp.t_startc;
-       tty->termios->c_cc[VSTOP] = tmp.t_stopc;
-       tty->termios->c_cc[VEOF] = tmp.t_eofc;
-       tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
-       mutex_unlock(&tty->termios_mutex);
-       return 0;
-}
-#endif
-
-#ifdef TIOCGLTC
-static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
-{
-       struct ltchars tmp;
-
-       mutex_lock(&tty->termios_mutex);
-       tmp.t_suspc = tty->termios->c_cc[VSUSP];
-       /* what is dsuspc anyway? */
-       tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
-       tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
-       /* what is flushc anyway? */
-       tmp.t_flushc = tty->termios->c_cc[VEOL2];
-       tmp.t_werasc = tty->termios->c_cc[VWERASE];
-       tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
-       mutex_unlock(&tty->termios_mutex);
-       return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
-}
-
-static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
-{
-       struct ltchars tmp;
-
-       if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
-               return -EFAULT;
-
-       mutex_lock(&tty->termios_mutex);
-       tty->termios->c_cc[VSUSP] = tmp.t_suspc;
-       /* what is dsuspc anyway? */
-       tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
-       tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
-       /* what is flushc anyway? */
-       tty->termios->c_cc[VEOL2] = tmp.t_flushc;
-       tty->termios->c_cc[VWERASE] = tmp.t_werasc;
-       tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
-       mutex_unlock(&tty->termios_mutex);
-       return 0;
-}
-#endif
-
-/**
- *     send_prio_char          -       send priority character
- *
- *     Send a high priority character to the tty even if stopped
- *
- *     Locking: none for xchar method, write ordering for write method.
- */
-
-static int send_prio_char(struct tty_struct *tty, char ch)
-{
-       int     was_stopped = tty->stopped;
-
-       if (tty->ops->send_xchar) {
-               tty->ops->send_xchar(tty, ch);
-               return 0;
-       }
-
-       if (tty_write_lock(tty, 0) < 0)
-               return -ERESTARTSYS;
-
-       if (was_stopped)
-               start_tty(tty);
-       tty->ops->write(tty, &ch, 1);
-       if (was_stopped)
-               stop_tty(tty);
-       tty_write_unlock(tty);
-       return 0;
-}
-
-/**
- *     tty_change_softcar      -       carrier change ioctl helper
- *     @tty: tty to update
- *     @arg: enable/disable CLOCAL
- *
- *     Perform a change to the CLOCAL state and call into the driver
- *     layer to make it visible. All done with the termios mutex
- */
-
-static int tty_change_softcar(struct tty_struct *tty, int arg)
-{
-       int ret = 0;
-       int bit = arg ? CLOCAL : 0;
-       struct ktermios old;
-
-       mutex_lock(&tty->termios_mutex);
-       old = *tty->termios;
-       tty->termios->c_cflag &= ~CLOCAL;
-       tty->termios->c_cflag |= bit;
-       if (tty->ops->set_termios)
-               tty->ops->set_termios(tty, &old);
-       if ((tty->termios->c_cflag & CLOCAL) != bit)
-               ret = -EINVAL;
-       mutex_unlock(&tty->termios_mutex);
-       return ret;
-}
-
-/**
- *     tty_mode_ioctl          -       mode related ioctls
- *     @tty: tty for the ioctl
- *     @file: file pointer for the tty
- *     @cmd: command
- *     @arg: ioctl argument
- *
- *     Perform non line discipline specific mode control ioctls. This
- *     is designed to be called by line disciplines to ensure they provide
- *     consistent mode setting.
- */
-
-int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
-                       unsigned int cmd, unsigned long arg)
-{
-       struct tty_struct *real_tty;
-       void __user *p = (void __user *)arg;
-       int ret = 0;
-       struct ktermios kterm;
-
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->driver->subtype == PTY_TYPE_MASTER)
-               real_tty = tty->link;
-       else
-               real_tty = tty;
-
-       switch (cmd) {
-#ifdef TIOCGETP
-       case TIOCGETP:
-               return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
-       case TIOCSETP:
-       case TIOCSETN:
-               return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
-#endif
-#ifdef TIOCGETC
-       case TIOCGETC:
-               return get_tchars(real_tty, p);
-       case TIOCSETC:
-               return set_tchars(real_tty, p);
-#endif
-#ifdef TIOCGLTC
-       case TIOCGLTC:
-               return get_ltchars(real_tty, p);
-       case TIOCSLTC:
-               return set_ltchars(real_tty, p);
-#endif
-       case TCSETSF:
-               return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
-       case TCSETSW:
-               return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
-       case TCSETS:
-               return set_termios(real_tty, p, TERMIOS_OLD);
-#ifndef TCGETS2
-       case TCGETS:
-               copy_termios(real_tty, &kterm);
-               if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
-                       ret = -EFAULT;
-               return ret;
-#else
-       case TCGETS:
-               copy_termios(real_tty, &kterm);
-               if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
-                       ret = -EFAULT;
-               return ret;
-       case TCGETS2:
-               copy_termios(real_tty, &kterm);
-               if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
-                       ret = -EFAULT;
-               return ret;
-       case TCSETSF2:
-               return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
-       case TCSETSW2:
-               return set_termios(real_tty, p, TERMIOS_WAIT);
-       case TCSETS2:
-               return set_termios(real_tty, p, 0);
-#endif
-       case TCGETA:
-               return get_termio(real_tty, p);
-       case TCSETAF:
-               return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
-       case TCSETAW:
-               return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
-       case TCSETA:
-               return set_termios(real_tty, p, TERMIOS_TERMIO);
-#ifndef TCGETS2
-       case TIOCGLCKTRMIOS:
-               copy_termios_locked(real_tty, &kterm);
-               if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
-                       ret = -EFAULT;
-               return ret;
-       case TIOCSLCKTRMIOS:
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               copy_termios_locked(real_tty, &kterm);
-               if (user_termios_to_kernel_termios(&kterm,
-                                              (struct termios __user *) arg))
-                       return -EFAULT;
-               mutex_lock(&real_tty->termios_mutex);
-               memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
-               mutex_unlock(&real_tty->termios_mutex);
-               return 0;
-#else
-       case TIOCGLCKTRMIOS:
-               copy_termios_locked(real_tty, &kterm);
-               if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
-                       ret = -EFAULT;
-               return ret;
-       case TIOCSLCKTRMIOS:
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               copy_termios_locked(real_tty, &kterm);
-               if (user_termios_to_kernel_termios_1(&kterm,
-                                              (struct termios __user *) arg))
-                       return -EFAULT;
-               mutex_lock(&real_tty->termios_mutex);
-               memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
-               mutex_unlock(&real_tty->termios_mutex);
-               return ret;
-#endif
-#ifdef TCGETX
-       case TCGETX: {
-               struct termiox ktermx;
-               if (real_tty->termiox == NULL)
-                       return -EINVAL;
-               mutex_lock(&real_tty->termios_mutex);
-               memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
-               mutex_unlock(&real_tty->termios_mutex);
-               if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
-                       ret = -EFAULT;
-               return ret;
-       }
-       case TCSETX:
-               return set_termiox(real_tty, p, 0);
-       case TCSETXW:
-               return set_termiox(real_tty, p, TERMIOS_WAIT);
-       case TCSETXF:
-               return set_termiox(real_tty, p, TERMIOS_FLUSH);
-#endif         
-       case TIOCGSOFTCAR:
-               copy_termios(real_tty, &kterm);
-               ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
-                                               (int __user *)arg);
-               return ret;
-       case TIOCSSOFTCAR:
-               if (get_user(arg, (unsigned int __user *) arg))
-                       return -EFAULT;
-               return tty_change_softcar(real_tty, arg);
-       default:
-               return -ENOIOCTLCMD;
-       }
-}
-EXPORT_SYMBOL_GPL(tty_mode_ioctl);
-
-int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
-{
-       struct tty_ldisc *ld;
-       int retval = tty_check_change(tty);
-       if (retval)
-               return retval;
-
-       ld = tty_ldisc_ref_wait(tty);
-       switch (arg) {
-       case TCIFLUSH:
-               if (ld && ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               break;
-       case TCIOFLUSH:
-               if (ld && ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               /* fall through */
-       case TCOFLUSH:
-               tty_driver_flush_buffer(tty);
-               break;
-       default:
-               tty_ldisc_deref(ld);
-               return -EINVAL;
-       }
-       tty_ldisc_deref(ld);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(tty_perform_flush);
-
-int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       unsigned long flags;
-       int retval;
-
-       switch (cmd) {
-       case TCXONC:
-               retval = tty_check_change(tty);
-               if (retval)
-                       return retval;
-               switch (arg) {
-               case TCOOFF:
-                       if (!tty->flow_stopped) {
-                               tty->flow_stopped = 1;
-                               stop_tty(tty);
-                       }
-                       break;
-               case TCOON:
-                       if (tty->flow_stopped) {
-                               tty->flow_stopped = 0;
-                               start_tty(tty);
-                       }
-                       break;
-               case TCIOFF:
-                       if (STOP_CHAR(tty) != __DISABLED_CHAR)
-                               return send_prio_char(tty, STOP_CHAR(tty));
-                       break;
-               case TCION:
-                       if (START_CHAR(tty) != __DISABLED_CHAR)
-                               return send_prio_char(tty, START_CHAR(tty));
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               return 0;
-       case TCFLSH:
-               return tty_perform_flush(tty, arg);
-       case TIOCPKT:
-       {
-               int pktmode;
-
-               if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
-                   tty->driver->subtype != PTY_TYPE_MASTER)
-                       return -ENOTTY;
-               if (get_user(pktmode, (int __user *) arg))
-                       return -EFAULT;
-               spin_lock_irqsave(&tty->ctrl_lock, flags);
-               if (pktmode) {
-                       if (!tty->packet) {
-                               tty->packet = 1;
-                               tty->link->ctrl_status = 0;
-                       }
-               } else
-                       tty->packet = 0;
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               return 0;
-       }
-       default:
-               /* Try the mode commands */
-               return tty_mode_ioctl(tty, file, cmd, arg);
-       }
-}
-EXPORT_SYMBOL(n_tty_ioctl_helper);
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
deleted file mode 100644 (file)
index 412f977..0000000
+++ /dev/null
@@ -1,915 +0,0 @@
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/devpts_fs.h>
-#include <linux/file.h>
-#include <linux/console.h>
-#include <linux/timer.h>
-#include <linux/ctype.h>
-#include <linux/kd.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/seq_file.h>
-
-#include <linux/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-
-#include <linux/smp_lock.h>    /* For the moment */
-
-#include <linux/kmod.h>
-#include <linux/nsproxy.h>
-
-/*
- *     This guards the refcounted line discipline lists. The lock
- *     must be taken with irqs off because there are hangup path
- *     callers who will do ldisc lookups and cannot sleep.
- */
-
-static DEFINE_SPINLOCK(tty_ldisc_lock);
-static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
-/* Line disc dispatch table */
-static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
-
-static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld)
-{
-       if (ld)
-               atomic_inc(&ld->users);
-       return ld;
-}
-
-static void put_ldisc(struct tty_ldisc *ld)
-{
-       unsigned long flags;
-
-       if (WARN_ON_ONCE(!ld))
-               return;
-
-       /*
-        * If this is the last user, free the ldisc, and
-        * release the ldisc ops.
-        *
-        * We really want an "atomic_dec_and_lock_irqsave()",
-        * but we don't have it, so this does it by hand.
-        */
-       local_irq_save(flags);
-       if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) {
-               struct tty_ldisc_ops *ldo = ld->ops;
-
-               ldo->refcount--;
-               module_put(ldo->owner);
-               spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
-               kfree(ld);
-               return;
-       }
-       local_irq_restore(flags);
-}
-
-/**
- *     tty_register_ldisc      -       install a line discipline
- *     @disc: ldisc number
- *     @new_ldisc: pointer to the ldisc object
- *
- *     Installs a new line discipline into the kernel. The discipline
- *     is set up as unreferenced and then made available to the kernel
- *     from this point onwards.
- *
- *     Locking:
- *             takes tty_ldisc_lock to guard against ldisc races
- */
-
-int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       if (disc < N_TTY || disc >= NR_LDISCS)
-               return -EINVAL;
-
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       tty_ldiscs[disc] = new_ldisc;
-       new_ldisc->num = disc;
-       new_ldisc->refcount = 0;
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
-       return ret;
-}
-EXPORT_SYMBOL(tty_register_ldisc);
-
-/**
- *     tty_unregister_ldisc    -       unload a line discipline
- *     @disc: ldisc number
- *     @new_ldisc: pointer to the ldisc object
- *
- *     Remove a line discipline from the kernel providing it is not
- *     currently in use.
- *
- *     Locking:
- *             takes tty_ldisc_lock to guard against ldisc races
- */
-
-int tty_unregister_ldisc(int disc)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       if (disc < N_TTY || disc >= NR_LDISCS)
-               return -EINVAL;
-
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       if (tty_ldiscs[disc]->refcount)
-               ret = -EBUSY;
-       else
-               tty_ldiscs[disc] = NULL;
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
-       return ret;
-}
-EXPORT_SYMBOL(tty_unregister_ldisc);
-
-static struct tty_ldisc_ops *get_ldops(int disc)
-{
-       unsigned long flags;
-       struct tty_ldisc_ops *ldops, *ret;
-
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       ret = ERR_PTR(-EINVAL);
-       ldops = tty_ldiscs[disc];
-       if (ldops) {
-               ret = ERR_PTR(-EAGAIN);
-               if (try_module_get(ldops->owner)) {
-                       ldops->refcount++;
-                       ret = ldops;
-               }
-       }
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-       return ret;
-}
-
-static void put_ldops(struct tty_ldisc_ops *ldops)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       ldops->refcount--;
-       module_put(ldops->owner);
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-}
-
-/**
- *     tty_ldisc_get           -       take a reference to an ldisc
- *     @disc: ldisc number
- *
- *     Takes a reference to a line discipline. Deals with refcounts and
- *     module locking counts. Returns NULL if the discipline is not available.
- *     Returns a pointer to the discipline and bumps the ref count if it is
- *     available
- *
- *     Locking:
- *             takes tty_ldisc_lock to guard against ldisc races
- */
-
-static struct tty_ldisc *tty_ldisc_get(int disc)
-{
-       struct tty_ldisc *ld;
-       struct tty_ldisc_ops *ldops;
-
-       if (disc < N_TTY || disc >= NR_LDISCS)
-               return ERR_PTR(-EINVAL);
-
-       /*
-        * Get the ldisc ops - we may need to request them to be loaded
-        * dynamically and try again.
-        */
-       ldops = get_ldops(disc);
-       if (IS_ERR(ldops)) {
-               request_module("tty-ldisc-%d", disc);
-               ldops = get_ldops(disc);
-               if (IS_ERR(ldops))
-                       return ERR_CAST(ldops);
-       }
-
-       ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
-       if (ld == NULL) {
-               put_ldops(ldops);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       ld->ops = ldops;
-       atomic_set(&ld->users, 1);
-       return ld;
-}
-
-static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
-{
-       return (*pos < NR_LDISCS) ? pos : NULL;
-}
-
-static void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
-{
-       (*pos)++;
-       return (*pos < NR_LDISCS) ? pos : NULL;
-}
-
-static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
-{
-}
-
-static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
-{
-       int i = *(loff_t *)v;
-       struct tty_ldisc_ops *ldops;
-
-       ldops = get_ldops(i);
-       if (IS_ERR(ldops))
-               return 0;
-       seq_printf(m, "%-10s %2d\n", ldops->name ? ldops->name : "???", i);
-       put_ldops(ldops);
-       return 0;
-}
-
-static const struct seq_operations tty_ldiscs_seq_ops = {
-       .start  = tty_ldiscs_seq_start,
-       .next   = tty_ldiscs_seq_next,
-       .stop   = tty_ldiscs_seq_stop,
-       .show   = tty_ldiscs_seq_show,
-};
-
-static int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &tty_ldiscs_seq_ops);
-}
-
-const struct file_operations tty_ldiscs_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = proc_tty_ldiscs_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
-/**
- *     tty_ldisc_assign        -       set ldisc on a tty
- *     @tty: tty to assign
- *     @ld: line discipline
- *
- *     Install an instance of a line discipline into a tty structure. The
- *     ldisc must have a reference count above zero to ensure it remains.
- *     The tty instance refcount starts at zero.
- *
- *     Locking:
- *             Caller must hold references
- */
-
-static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
-{
-       tty->ldisc = ld;
-}
-
-/**
- *     tty_ldisc_try           -       internal helper
- *     @tty: the tty
- *
- *     Make a single attempt to grab and bump the refcount on
- *     the tty ldisc. Return 0 on failure or 1 on success. This is
- *     used to implement both the waiting and non waiting versions
- *     of tty_ldisc_ref
- *
- *     Locking: takes tty_ldisc_lock
- */
-
-static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
-{
-       unsigned long flags;
-       struct tty_ldisc *ld;
-
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       ld = NULL;
-       if (test_bit(TTY_LDISC, &tty->flags))
-               ld = get_ldisc(tty->ldisc);
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-       return ld;
-}
-
-/**
- *     tty_ldisc_ref_wait      -       wait for the tty ldisc
- *     @tty: tty device
- *
- *     Dereference the line discipline for the terminal and take a
- *     reference to it. If the line discipline is in flux then
- *     wait patiently until it changes.
- *
- *     Note: Must not be called from an IRQ/timer context. The caller
- *     must also be careful not to hold other locks that will deadlock
- *     against a discipline change, such as an existing ldisc reference
- *     (which we check for)
- *
- *     Locking: call functions take tty_ldisc_lock
- */
-
-struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
-{
-       struct tty_ldisc *ld;
-
-       /* wait_event is a macro */
-       wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL);
-       return ld;
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
-
-/**
- *     tty_ldisc_ref           -       get the tty ldisc
- *     @tty: tty device
- *
- *     Dereference the line discipline for the terminal and take a
- *     reference to it. If the line discipline is in flux then
- *     return NULL. Can be called from IRQ and timer functions.
- *
- *     Locking: called functions take tty_ldisc_lock
- */
-
-struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
-{
-       return tty_ldisc_try(tty);
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_ref);
-
-/**
- *     tty_ldisc_deref         -       free a tty ldisc reference
- *     @ld: reference to free up
- *
- *     Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May
- *     be called in IRQ context.
- *
- *     Locking: takes tty_ldisc_lock
- */
-
-void tty_ldisc_deref(struct tty_ldisc *ld)
-{
-       put_ldisc(ld);
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_deref);
-
-static inline void tty_ldisc_put(struct tty_ldisc *ld)
-{
-       put_ldisc(ld);
-}
-
-/**
- *     tty_ldisc_enable        -       allow ldisc use
- *     @tty: terminal to activate ldisc on
- *
- *     Set the TTY_LDISC flag when the line discipline can be called
- *     again. Do necessary wakeups for existing sleepers. Clear the LDISC
- *     changing flag to indicate any ldisc change is now over.
- *
- *     Note: nobody should set the TTY_LDISC bit except via this function.
- *     Clearing directly is allowed.
- */
-
-void tty_ldisc_enable(struct tty_struct *tty)
-{
-       set_bit(TTY_LDISC, &tty->flags);
-       clear_bit(TTY_LDISC_CHANGING, &tty->flags);
-       wake_up(&tty_ldisc_wait);
-}
-
-/**
- *     tty_ldisc_flush -       flush line discipline queue
- *     @tty: tty
- *
- *     Flush the line discipline queue (if any) for this tty. If there
- *     is no line discipline active this is a no-op.
- */
-
-void tty_ldisc_flush(struct tty_struct *tty)
-{
-       struct tty_ldisc *ld = tty_ldisc_ref(tty);
-       if (ld) {
-               if (ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               tty_ldisc_deref(ld);
-       }
-       tty_buffer_flush(tty);
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_flush);
-
-/**
- *     tty_set_termios_ldisc           -       set ldisc field
- *     @tty: tty structure
- *     @num: line discipline number
- *
- *     This is probably overkill for real world processors but
- *     they are not on hot paths so a little discipline won't do
- *     any harm.
- *
- *     Locking: takes termios_mutex
- */
-
-static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
-{
-       mutex_lock(&tty->termios_mutex);
-       tty->termios->c_line = num;
-       mutex_unlock(&tty->termios_mutex);
-}
-
-/**
- *     tty_ldisc_open          -       open a line discipline
- *     @tty: tty we are opening the ldisc on
- *     @ld: discipline to open
- *
- *     A helper opening method. Also a convenient debugging and check
- *     point.
- *
- *     Locking: always called with BTM already held.
- */
-
-static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
-{
-       WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
-       if (ld->ops->open) {
-               int ret;
-                /* BTM here locks versus a hangup event */
-               WARN_ON(!tty_locked());
-               ret = ld->ops->open(tty);
-               return ret;
-       }
-       return 0;
-}
-
-/**
- *     tty_ldisc_close         -       close a line discipline
- *     @tty: tty we are opening the ldisc on
- *     @ld: discipline to close
- *
- *     A helper close method. Also a convenient debugging and check
- *     point.
- */
-
-static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
-{
-       WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
-       clear_bit(TTY_LDISC_OPEN, &tty->flags);
-       if (ld->ops->close)
-               ld->ops->close(tty);
-}
-
-/**
- *     tty_ldisc_restore       -       helper for tty ldisc change
- *     @tty: tty to recover
- *     @old: previous ldisc
- *
- *     Restore the previous line discipline or N_TTY when a line discipline
- *     change fails due to an open error
- */
-
-static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
-{
-       char buf[64];
-       struct tty_ldisc *new_ldisc;
-       int r;
-
-       /* There is an outstanding reference here so this is safe */
-       old = tty_ldisc_get(old->ops->num);
-       WARN_ON(IS_ERR(old));
-       tty_ldisc_assign(tty, old);
-       tty_set_termios_ldisc(tty, old->ops->num);
-       if (tty_ldisc_open(tty, old) < 0) {
-               tty_ldisc_put(old);
-               /* This driver is always present */
-               new_ldisc = tty_ldisc_get(N_TTY);
-               if (IS_ERR(new_ldisc))
-                       panic("n_tty: get");
-               tty_ldisc_assign(tty, new_ldisc);
-               tty_set_termios_ldisc(tty, N_TTY);
-               r = tty_ldisc_open(tty, new_ldisc);
-               if (r < 0)
-                       panic("Couldn't open N_TTY ldisc for "
-                             "%s --- error %d.",
-                             tty_name(tty, buf), r);
-       }
-}
-
-/**
- *     tty_ldisc_halt          -       shut down the line discipline
- *     @tty: tty device
- *
- *     Shut down the line discipline and work queue for this tty device.
- *     The TTY_LDISC flag being cleared ensures no further references can
- *     be obtained while the delayed work queue halt ensures that no more
- *     data is fed to the ldisc.
- *
- *     You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex)
- *     in order to make sure any currently executing ldisc work is also
- *     flushed.
- */
-
-static int tty_ldisc_halt(struct tty_struct *tty)
-{
-       clear_bit(TTY_LDISC, &tty->flags);
-       return cancel_delayed_work_sync(&tty->buf.work);
-}
-
-/**
- *     tty_set_ldisc           -       set line discipline
- *     @tty: the terminal to set
- *     @ldisc: the line discipline
- *
- *     Set the discipline of a tty line. Must be called from a process
- *     context. The ldisc change logic has to protect itself against any
- *     overlapping ldisc change (including on the other end of pty pairs),
- *     the close of one side of a tty/pty pair, and eventually hangup.
- *
- *     Locking: takes tty_ldisc_lock, termios_mutex
- */
-
-int tty_set_ldisc(struct tty_struct *tty, int ldisc)
-{
-       int retval;
-       struct tty_ldisc *o_ldisc, *new_ldisc;
-       int work, o_work = 0;
-       struct tty_struct *o_tty;
-
-       new_ldisc = tty_ldisc_get(ldisc);
-       if (IS_ERR(new_ldisc))
-               return PTR_ERR(new_ldisc);
-
-       tty_lock();
-       /*
-        *      We need to look at the tty locking here for pty/tty pairs
-        *      when both sides try to change in parallel.
-        */
-
-       o_tty = tty->link;      /* o_tty is the pty side or NULL */
-
-
-       /*
-        *      Check the no-op case
-        */
-
-       if (tty->ldisc->ops->num == ldisc) {
-               tty_unlock();
-               tty_ldisc_put(new_ldisc);
-               return 0;
-       }
-
-       tty_unlock();
-       /*
-        *      Problem: What do we do if this blocks ?
-        *      We could deadlock here
-        */
-
-       tty_wait_until_sent(tty, 0);
-
-       tty_lock();
-       mutex_lock(&tty->ldisc_mutex);
-
-       /*
-        *      We could be midstream of another ldisc change which has
-        *      dropped the lock during processing. If so we need to wait.
-        */
-
-       while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
-               mutex_unlock(&tty->ldisc_mutex);
-               tty_unlock();
-               wait_event(tty_ldisc_wait,
-                       test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
-               tty_lock();
-               mutex_lock(&tty->ldisc_mutex);
-       }
-
-       set_bit(TTY_LDISC_CHANGING, &tty->flags);
-
-       /*
-        *      No more input please, we are switching. The new ldisc
-        *      will update this value in the ldisc open function
-        */
-
-       tty->receive_room = 0;
-
-       o_ldisc = tty->ldisc;
-
-       tty_unlock();
-       /*
-        *      Make sure we don't change while someone holds a
-        *      reference to the line discipline. The TTY_LDISC bit
-        *      prevents anyone taking a reference once it is clear.
-        *      We need the lock to avoid racing reference takers.
-        *
-        *      We must clear the TTY_LDISC bit here to avoid a livelock
-        *      with a userspace app continually trying to use the tty in
-        *      parallel to the change and re-referencing the tty.
-        */
-
-       work = tty_ldisc_halt(tty);
-       if (o_tty)
-               o_work = tty_ldisc_halt(o_tty);
-
-       /*
-        * Wait for ->hangup_work and ->buf.work handlers to terminate.
-        * We must drop the mutex here in case a hangup is also in process.
-        */
-
-       mutex_unlock(&tty->ldisc_mutex);
-
-       flush_scheduled_work();
-
-       tty_lock();
-       mutex_lock(&tty->ldisc_mutex);
-       if (test_bit(TTY_HUPPED, &tty->flags)) {
-               /* We were raced by the hangup method. It will have stomped
-                  the ldisc data and closed the ldisc down */
-               clear_bit(TTY_LDISC_CHANGING, &tty->flags);
-               mutex_unlock(&tty->ldisc_mutex);
-               tty_ldisc_put(new_ldisc);
-               tty_unlock();
-               return -EIO;
-       }
-
-       /* Shutdown the current discipline. */
-       tty_ldisc_close(tty, o_ldisc);
-
-       /* Now set up the new line discipline. */
-       tty_ldisc_assign(tty, new_ldisc);
-       tty_set_termios_ldisc(tty, ldisc);
-
-       retval = tty_ldisc_open(tty, new_ldisc);
-       if (retval < 0) {
-               /* Back to the old one or N_TTY if we can't */
-               tty_ldisc_put(new_ldisc);
-               tty_ldisc_restore(tty, o_ldisc);
-       }
-
-       /* At this point we hold a reference to the new ldisc and a
-          a reference to the old ldisc. If we ended up flipping back
-          to the existing ldisc we have two references to it */
-
-       if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc)
-               tty->ops->set_ldisc(tty);
-
-       tty_ldisc_put(o_ldisc);
-
-       /*
-        *      Allow ldisc referencing to occur again
-        */
-
-       tty_ldisc_enable(tty);
-       if (o_tty)
-               tty_ldisc_enable(o_tty);
-
-       /* Restart the work queue in case no characters kick it off. Safe if
-          already running */
-       if (work)
-               schedule_delayed_work(&tty->buf.work, 1);
-       if (o_work)
-               schedule_delayed_work(&o_tty->buf.work, 1);
-       mutex_unlock(&tty->ldisc_mutex);
-       tty_unlock();
-       return retval;
-}
-
-/**
- *     tty_reset_termios       -       reset terminal state
- *     @tty: tty to reset
- *
- *     Restore a terminal to the driver default state.
- */
-
-static void tty_reset_termios(struct tty_struct *tty)
-{
-       mutex_lock(&tty->termios_mutex);
-       *tty->termios = tty->driver->init_termios;
-       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
-       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
-       mutex_unlock(&tty->termios_mutex);
-}
-
-
-/**
- *     tty_ldisc_reinit        -       reinitialise the tty ldisc
- *     @tty: tty to reinit
- *     @ldisc: line discipline to reinitialize
- *
- *     Switch the tty to a line discipline and leave the ldisc
- *     state closed
- */
-
-static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
-{
-       struct tty_ldisc *ld;
-
-       tty_ldisc_close(tty, tty->ldisc);
-       tty_ldisc_put(tty->ldisc);
-       tty->ldisc = NULL;
-       /*
-        *      Switch the line discipline back
-        */
-       ld = tty_ldisc_get(ldisc);
-       BUG_ON(IS_ERR(ld));
-       tty_ldisc_assign(tty, ld);
-       tty_set_termios_ldisc(tty, ldisc);
-}
-
-/**
- *     tty_ldisc_hangup                -       hangup ldisc reset
- *     @tty: tty being hung up
- *
- *     Some tty devices reset their termios when they receive a hangup
- *     event. In that situation we must also switch back to N_TTY properly
- *     before we reset the termios data.
- *
- *     Locking: We can take the ldisc mutex as the rest of the code is
- *     careful to allow for this.
- *
- *     In the pty pair case this occurs in the close() path of the
- *     tty itself so we must be careful about locking rules.
- */
-
-void tty_ldisc_hangup(struct tty_struct *tty)
-{
-       struct tty_ldisc *ld;
-       int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
-       int err = 0;
-
-       /*
-        * FIXME! What are the locking issues here? This may me overdoing
-        * things... This question is especially important now that we've
-        * removed the irqlock.
-        */
-       ld = tty_ldisc_ref(tty);
-       if (ld != NULL) {
-               /* We may have no line discipline at this point */
-               if (ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               tty_driver_flush_buffer(tty);
-               if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
-                   ld->ops->write_wakeup)
-                       ld->ops->write_wakeup(tty);
-               if (ld->ops->hangup)
-                       ld->ops->hangup(tty);
-               tty_ldisc_deref(ld);
-       }
-       /*
-        * FIXME: Once we trust the LDISC code better we can wait here for
-        * ldisc completion and fix the driver call race
-        */
-       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
-       wake_up_interruptible_poll(&tty->read_wait, POLLIN);
-       /*
-        * Shutdown the current line discipline, and reset it to
-        * N_TTY if need be.
-        *
-        * Avoid racing set_ldisc or tty_ldisc_release
-        */
-       mutex_lock(&tty->ldisc_mutex);
-
-       /*
-        * this is like tty_ldisc_halt, but we need to give up
-        * the BTM before calling cancel_delayed_work_sync,
-        * which may need to wait for another function taking the BTM
-        */
-       clear_bit(TTY_LDISC, &tty->flags);
-       tty_unlock();
-       cancel_delayed_work_sync(&tty->buf.work);
-       mutex_unlock(&tty->ldisc_mutex);
-
-       tty_lock();
-       mutex_lock(&tty->ldisc_mutex);
-
-       /* At this point we have a closed ldisc and we want to
-          reopen it. We could defer this to the next open but
-          it means auditing a lot of other paths so this is
-          a FIXME */
-       if (tty->ldisc) {       /* Not yet closed */
-               if (reset == 0) {
-                       tty_ldisc_reinit(tty, tty->termios->c_line);
-                       err = tty_ldisc_open(tty, tty->ldisc);
-               }
-               /* If the re-open fails or we reset then go to N_TTY. The
-                  N_TTY open cannot fail */
-               if (reset || err) {
-                       tty_ldisc_reinit(tty, N_TTY);
-                       WARN_ON(tty_ldisc_open(tty, tty->ldisc));
-               }
-               tty_ldisc_enable(tty);
-       }
-       mutex_unlock(&tty->ldisc_mutex);
-       if (reset)
-               tty_reset_termios(tty);
-}
-
-/**
- *     tty_ldisc_setup                 -       open line discipline
- *     @tty: tty being shut down
- *     @o_tty: pair tty for pty/tty pairs
- *
- *     Called during the initial open of a tty/pty pair in order to set up the
- *     line disciplines and bind them to the tty. This has no locking issues
- *     as the device isn't yet active.
- */
-
-int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
-{
-       struct tty_ldisc *ld = tty->ldisc;
-       int retval;
-
-       retval = tty_ldisc_open(tty, ld);
-       if (retval)
-               return retval;
-
-       if (o_tty) {
-               retval = tty_ldisc_open(o_tty, o_tty->ldisc);
-               if (retval) {
-                       tty_ldisc_close(tty, ld);
-                       return retval;
-               }
-               tty_ldisc_enable(o_tty);
-       }
-       tty_ldisc_enable(tty);
-       return 0;
-}
-/**
- *     tty_ldisc_release               -       release line discipline
- *     @tty: tty being shut down
- *     @o_tty: pair tty for pty/tty pairs
- *
- *     Called during the final close of a tty/pty pair in order to shut down
- *     the line discpline layer. On exit the ldisc assigned is N_TTY and the
- *     ldisc has not been opened.
- */
-
-void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
-{
-       /*
-        * Prevent flush_to_ldisc() from rescheduling the work for later.  Then
-        * kill any delayed work. As this is the final close it does not
-        * race with the set_ldisc code path.
-        */
-
-       tty_unlock();
-       tty_ldisc_halt(tty);
-       flush_scheduled_work();
-       tty_lock();
-
-       mutex_lock(&tty->ldisc_mutex);
-       /*
-        * Now kill off the ldisc
-        */
-       tty_ldisc_close(tty, tty->ldisc);
-       tty_ldisc_put(tty->ldisc);
-       /* Force an oops if we mess this up */
-       tty->ldisc = NULL;
-
-       /* Ensure the next open requests the N_TTY ldisc */
-       tty_set_termios_ldisc(tty, N_TTY);
-       mutex_unlock(&tty->ldisc_mutex);
-
-       /* This will need doing differently if we need to lock */
-       if (o_tty)
-               tty_ldisc_release(o_tty, NULL);
-
-       /* And the memory resources remaining (buffers, termios) will be
-          disposed of when the kref hits zero */
-}
-
-/**
- *     tty_ldisc_init          -       ldisc setup for new tty
- *     @tty: tty being allocated
- *
- *     Set up the line discipline objects for a newly allocated tty. Note that
- *     the tty structure is not completely set up when this call is made.
- */
-
-void tty_ldisc_init(struct tty_struct *tty)
-{
-       struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
-       if (IS_ERR(ld))
-               panic("n_tty: init_tty");
-       tty_ldisc_assign(tty, ld);
-}
-
-void tty_ldisc_begin(void)
-{
-       /* Setup the default TTY line discipline. */
-       (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
-}
diff --git a/drivers/char/tty_mutex.c b/drivers/char/tty_mutex.c
deleted file mode 100644 (file)
index 1336975..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * drivers/char/tty_lock.c
- */
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/kallsyms.h>
-#include <linux/semaphore.h>
-#include <linux/sched.h>
-
-/*
- * The 'big tty mutex'
- *
- * This mutex is taken and released by tty_lock() and tty_unlock(),
- * replacing the older big kernel lock.
- * It can no longer be taken recursively, and does not get
- * released implicitly while sleeping.
- *
- * Don't use in new code.
- */
-static DEFINE_MUTEX(big_tty_mutex);
-struct task_struct *__big_tty_mutex_owner;
-EXPORT_SYMBOL_GPL(__big_tty_mutex_owner);
-
-/*
- * Getting the big tty mutex.
- */
-void __lockfunc tty_lock(void)
-{
-       struct task_struct *task = current;
-
-       WARN_ON(__big_tty_mutex_owner == task);
-
-       mutex_lock(&big_tty_mutex);
-       __big_tty_mutex_owner = task;
-}
-EXPORT_SYMBOL(tty_lock);
-
-void __lockfunc tty_unlock(void)
-{
-       struct task_struct *task = current;
-
-       WARN_ON(__big_tty_mutex_owner != task);
-       __big_tty_mutex_owner = NULL;
-
-       mutex_unlock(&big_tty_mutex);
-}
-EXPORT_SYMBOL(tty_unlock);
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
deleted file mode 100644 (file)
index 33d37d2..0000000
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Tty port functions
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-
-void tty_port_init(struct tty_port *port)
-{
-       memset(port, 0, sizeof(*port));
-       init_waitqueue_head(&port->open_wait);
-       init_waitqueue_head(&port->close_wait);
-       init_waitqueue_head(&port->delta_msr_wait);
-       mutex_init(&port->mutex);
-       mutex_init(&port->buf_mutex);
-       spin_lock_init(&port->lock);
-       port->close_delay = (50 * HZ) / 100;
-       port->closing_wait = (3000 * HZ) / 100;
-       kref_init(&port->kref);
-}
-EXPORT_SYMBOL(tty_port_init);
-
-int tty_port_alloc_xmit_buf(struct tty_port *port)
-{
-       /* We may sleep in get_zeroed_page() */
-       mutex_lock(&port->buf_mutex);
-       if (port->xmit_buf == NULL)
-               port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
-       mutex_unlock(&port->buf_mutex);
-       if (port->xmit_buf == NULL)
-               return -ENOMEM;
-       return 0;
-}
-EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
-
-void tty_port_free_xmit_buf(struct tty_port *port)
-{
-       mutex_lock(&port->buf_mutex);
-       if (port->xmit_buf != NULL) {
-               free_page((unsigned long)port->xmit_buf);
-               port->xmit_buf = NULL;
-       }
-       mutex_unlock(&port->buf_mutex);
-}
-EXPORT_SYMBOL(tty_port_free_xmit_buf);
-
-static void tty_port_destructor(struct kref *kref)
-{
-       struct tty_port *port = container_of(kref, struct tty_port, kref);
-       if (port->xmit_buf)
-               free_page((unsigned long)port->xmit_buf);
-       if (port->ops->destruct)
-               port->ops->destruct(port);
-       else
-               kfree(port);
-}
-
-void tty_port_put(struct tty_port *port)
-{
-       if (port)
-               kref_put(&port->kref, tty_port_destructor);
-}
-EXPORT_SYMBOL(tty_port_put);
-
-/**
- *     tty_port_tty_get        -       get a tty reference
- *     @port: tty port
- *
- *     Return a refcount protected tty instance or NULL if the port is not
- *     associated with a tty (eg due to close or hangup)
- */
-
-struct tty_struct *tty_port_tty_get(struct tty_port *port)
-{
-       unsigned long flags;
-       struct tty_struct *tty;
-
-       spin_lock_irqsave(&port->lock, flags);
-       tty = tty_kref_get(port->tty);
-       spin_unlock_irqrestore(&port->lock, flags);
-       return tty;
-}
-EXPORT_SYMBOL(tty_port_tty_get);
-
-/**
- *     tty_port_tty_set        -       set the tty of a port
- *     @port: tty port
- *     @tty: the tty
- *
- *     Associate the port and tty pair. Manages any internal refcounts.
- *     Pass NULL to deassociate a port
- */
-
-void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       if (port->tty)
-               tty_kref_put(port->tty);
-       port->tty = tty_kref_get(tty);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-EXPORT_SYMBOL(tty_port_tty_set);
-
-static void tty_port_shutdown(struct tty_port *port)
-{
-       mutex_lock(&port->mutex);
-       if (port->ops->shutdown && !port->console &&
-               test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
-                       port->ops->shutdown(port);
-       mutex_unlock(&port->mutex);
-}
-
-/**
- *     tty_port_hangup         -       hangup helper
- *     @port: tty port
- *
- *     Perform port level tty hangup flag and count changes. Drop the tty
- *     reference.
- */
-
-void tty_port_hangup(struct tty_port *port)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       port->count = 0;
-       port->flags &= ~ASYNC_NORMAL_ACTIVE;
-       if (port->tty) {
-               set_bit(TTY_IO_ERROR, &port->tty->flags);
-               tty_kref_put(port->tty);
-       }
-       port->tty = NULL;
-       spin_unlock_irqrestore(&port->lock, flags);
-       wake_up_interruptible(&port->open_wait);
-       wake_up_interruptible(&port->delta_msr_wait);
-       tty_port_shutdown(port);
-}
-EXPORT_SYMBOL(tty_port_hangup);
-
-/**
- *     tty_port_carrier_raised -       carrier raised check
- *     @port: tty port
- *
- *     Wrapper for the carrier detect logic. For the moment this is used
- *     to hide some internal details. This will eventually become entirely
- *     internal to the tty port.
- */
-
-int tty_port_carrier_raised(struct tty_port *port)
-{
-       if (port->ops->carrier_raised == NULL)
-               return 1;
-       return port->ops->carrier_raised(port);
-}
-EXPORT_SYMBOL(tty_port_carrier_raised);
-
-/**
- *     tty_port_raise_dtr_rts  -       Raise DTR/RTS
- *     @port: tty port
- *
- *     Wrapper for the DTR/RTS raise logic. For the moment this is used
- *     to hide some internal details. This will eventually become entirely
- *     internal to the tty port.
- */
-
-void tty_port_raise_dtr_rts(struct tty_port *port)
-{
-       if (port->ops->dtr_rts)
-               port->ops->dtr_rts(port, 1);
-}
-EXPORT_SYMBOL(tty_port_raise_dtr_rts);
-
-/**
- *     tty_port_lower_dtr_rts  -       Lower DTR/RTS
- *     @port: tty port
- *
- *     Wrapper for the DTR/RTS raise logic. For the moment this is used
- *     to hide some internal details. This will eventually become entirely
- *     internal to the tty port.
- */
-
-void tty_port_lower_dtr_rts(struct tty_port *port)
-{
-       if (port->ops->dtr_rts)
-               port->ops->dtr_rts(port, 0);
-}
-EXPORT_SYMBOL(tty_port_lower_dtr_rts);
-
-/**
- *     tty_port_block_til_ready        -       Waiting logic for tty open
- *     @port: the tty port being opened
- *     @tty: the tty device being bound
- *     @filp: the file pointer of the opener
- *
- *     Implement the core POSIX/SuS tty behaviour when opening a tty device.
- *     Handles:
- *             - hangup (both before and during)
- *             - non blocking open
- *             - rts/dtr/dcd
- *             - signals
- *             - port flags and counts
- *
- *     The passed tty_port must implement the carrier_raised method if it can
- *     do carrier detect and the dtr_rts method if it supports software
- *     management of these lines. Note that the dtr/rts raise is done each
- *     iteration as a hangup may have previously dropped them while we wait.
- */
-
-int tty_port_block_til_ready(struct tty_port *port,
-                               struct tty_struct *tty, struct file *filp)
-{
-       int do_clocal = 0, retval;
-       unsigned long flags;
-       DEFINE_WAIT(wait);
-       int cd;
-
-       /* block if port is in the process of being closed */
-       if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
-               wait_event_interruptible_tty(port->close_wait,
-                               !(port->flags & ASYNC_CLOSING));
-               if (port->flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-       }
-
-       /* if non-blocking mode is set we can pass directly to open unless
-          the port has just hung up or is in another error state */
-       if (tty->flags & (1 << TTY_IO_ERROR)) {
-               port->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-       if (filp->f_flags & O_NONBLOCK) {
-               /* Indicate we are open */
-               if (tty->termios->c_cflag & CBAUD)
-                       tty_port_raise_dtr_rts(port);
-               port->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (C_CLOCAL(tty))
-               do_clocal = 1;
-
-       /* Block waiting until we can proceed. We may need to wait for the
-          carrier, but we must also wait for any close that is in progress
-          before the next open may complete */
-
-       retval = 0;
-
-       /* The port lock protects the port counts */
-       spin_lock_irqsave(&port->lock, flags);
-       if (!tty_hung_up_p(filp))
-               port->count--;
-       port->blocked_open++;
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       while (1) {
-               /* Indicate we are open */
-               if (tty->termios->c_cflag & CBAUD)
-                       tty_port_raise_dtr_rts(port);
-
-               prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
-               /* Check for a hangup or uninitialised port.
-                                                       Return accordingly */
-               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
-                       if (port->flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;
-                       break;
-               }
-               /* Probe the carrier. For devices with no carrier detect this
-                  will always return true */
-               cd = tty_port_carrier_raised(port);
-               if (!(port->flags & ASYNC_CLOSING) &&
-                               (do_clocal || cd))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               tty_unlock();
-               schedule();
-               tty_lock();
-       }
-       finish_wait(&port->open_wait, &wait);
-
-       /* Update counts. A parallel hangup will have set count to zero and
-          we must not mess that up further */
-       spin_lock_irqsave(&port->lock, flags);
-       if (!tty_hung_up_p(filp))
-               port->count++;
-       port->blocked_open--;
-       if (retval == 0)
-               port->flags |= ASYNC_NORMAL_ACTIVE;
-       spin_unlock_irqrestore(&port->lock, flags);
-       return retval;
-}
-EXPORT_SYMBOL(tty_port_block_til_ready);
-
-int tty_port_close_start(struct tty_port *port,
-                               struct tty_struct *tty, struct file *filp)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               return 0;
-       }
-
-       if (tty->count == 1 && port->count != 1) {
-               printk(KERN_WARNING
-                   "tty_port_close_start: tty->count = 1 port count = %d.\n",
-                                                               port->count);
-               port->count = 1;
-       }
-       if (--port->count < 0) {
-               printk(KERN_WARNING "tty_port_close_start: count = %d\n",
-                                                               port->count);
-               port->count = 0;
-       }
-
-       if (port->count) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               if (port->ops->drop)
-                       port->ops->drop(port);
-               return 0;
-       }
-       set_bit(ASYNCB_CLOSING, &port->flags);
-       tty->closing = 1;
-       spin_unlock_irqrestore(&port->lock, flags);
-       /* Don't block on a stalled port, just pull the chain */
-       if (tty->flow_stopped)
-               tty_driver_flush_buffer(tty);
-       if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
-                       port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, port->closing_wait);
-       if (port->drain_delay) {
-               unsigned int bps = tty_get_baud_rate(tty);
-               long timeout;
-
-               if (bps > 1200)
-                       timeout = max_t(long,
-                               (HZ * 10 * port->drain_delay) / bps, HZ / 10);
-               else
-                       timeout = 2 * HZ;
-               schedule_timeout_interruptible(timeout);
-       }
-       /* Flush the ldisc buffering */
-       tty_ldisc_flush(tty);
-
-       /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
-          hang up the line */
-       if (tty->termios->c_cflag & HUPCL)
-               tty_port_lower_dtr_rts(port);
-
-       /* Don't call port->drop for the last reference. Callers will want
-          to drop the last active reference in ->shutdown() or the tty
-          shutdown path */
-       return 1;
-}
-EXPORT_SYMBOL(tty_port_close_start);
-
-void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       tty->closing = 0;
-
-       if (port->blocked_open) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               if (port->close_delay) {
-                       msleep_interruptible(
-                               jiffies_to_msecs(port->close_delay));
-               }
-               spin_lock_irqsave(&port->lock, flags);
-               wake_up_interruptible(&port->open_wait);
-       }
-       port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
-       wake_up_interruptible(&port->close_wait);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-EXPORT_SYMBOL(tty_port_close_end);
-
-void tty_port_close(struct tty_port *port, struct tty_struct *tty,
-                                                       struct file *filp)
-{
-       if (tty_port_close_start(port, tty, filp) == 0)
-               return;
-       tty_port_shutdown(port);
-       set_bit(TTY_IO_ERROR, &tty->flags);
-       tty_port_close_end(port, tty);
-       tty_port_tty_set(port, NULL);
-}
-EXPORT_SYMBOL(tty_port_close);
-
-int tty_port_open(struct tty_port *port, struct tty_struct *tty,
-                                                       struct file *filp)
-{
-       spin_lock_irq(&port->lock);
-       if (!tty_hung_up_p(filp))
-               ++port->count;
-       spin_unlock_irq(&port->lock);
-       tty_port_tty_set(port, tty);
-
-       /*
-        * Do the device-specific open only if the hardware isn't
-        * already initialized. Serialize open and shutdown using the
-        * port mutex.
-        */
-
-       mutex_lock(&port->mutex);
-
-       if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
-               clear_bit(TTY_IO_ERROR, &tty->flags);
-               if (port->ops->activate) {
-                       int retval = port->ops->activate(port, tty);
-                       if (retval) {
-                               mutex_unlock(&port->mutex);
-                               return retval;
-                       }
-               }
-               set_bit(ASYNCB_INITIALIZED, &port->flags);
-       }
-       mutex_unlock(&port->mutex);
-       return tty_port_block_til_ready(port, tty, filp);
-}
-
-EXPORT_SYMBOL(tty_port_open);
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
deleted file mode 100644 (file)
index 273ab44..0000000
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
- * linux/drivers/char/vc_screen.c
- *
- * Provide access to virtual console memory.
- * /dev/vcs0: the screen as it is being viewed right now (possibly scrolled)
- * /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63)
- *            [minor: N]
- *
- * /dev/vcsaN: idem, but including attributes, and prefixed with
- *     the 4 bytes lines,columns,x,y (as screendump used to give).
- *     Attribute/character pair is in native endianity.
- *            [minor: N+128]
- *
- * This replaces screendump and part of selection, so that the system
- * administrator can control access using file system permissions.
- *
- * aeb@cwi.nl - efter Friedas begravelse - 950211
- *
- * machek@k332.feld.cvut.cz - modified not to send characters to wrong console
- *      - fixed some fatal off-by-one bugs (0-- no longer == -1 -> looping and looping and looping...)
- *      - making it shorter - scr_readw are macros which expand in PRETTY long code
- */
-
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-#include <linux/kbd_kern.h>
-#include <linux/console.h>
-#include <linux/device.h>
-#include <linux/smp_lock.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/signal.h>
-#include <linux/slab.h>
-#include <linux/notifier.h>
-
-#include <asm/uaccess.h>
-#include <asm/byteorder.h>
-#include <asm/unaligned.h>
-
-#undef attr
-#undef org
-#undef addr
-#define HEADER_SIZE    4
-
-struct vcs_poll_data {
-       struct notifier_block notifier;
-       unsigned int cons_num;
-       bool seen_last_update;
-       wait_queue_head_t waitq;
-       struct fasync_struct *fasync;
-};
-
-static int
-vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param)
-{
-       struct vt_notifier_param *param = _param;
-       struct vc_data *vc = param->vc;
-       struct vcs_poll_data *poll =
-               container_of(nb, struct vcs_poll_data, notifier);
-       int currcons = poll->cons_num;
-
-       if (code != VT_UPDATE)
-               return NOTIFY_DONE;
-
-       if (currcons == 0)
-               currcons = fg_console;
-       else
-               currcons--;
-       if (currcons != vc->vc_num)
-               return NOTIFY_DONE;
-
-       poll->seen_last_update = false;
-       wake_up_interruptible(&poll->waitq);
-       kill_fasync(&poll->fasync, SIGIO, POLL_IN);
-       return NOTIFY_OK;
-}
-
-static void
-vcs_poll_data_free(struct vcs_poll_data *poll)
-{
-       unregister_vt_notifier(&poll->notifier);
-       kfree(poll);
-}
-
-static struct vcs_poll_data *
-vcs_poll_data_get(struct file *file)
-{
-       struct vcs_poll_data *poll = file->private_data;
-
-       if (poll)
-               return poll;
-
-       poll = kzalloc(sizeof(*poll), GFP_KERNEL);
-       if (!poll)
-               return NULL;
-       poll->cons_num = iminor(file->f_path.dentry->d_inode) & 127;
-       init_waitqueue_head(&poll->waitq);
-       poll->notifier.notifier_call = vcs_notifier;
-       if (register_vt_notifier(&poll->notifier) != 0) {
-               kfree(poll);
-               return NULL;
-       }
-
-       /*
-        * This code may be called either through ->poll() or ->fasync().
-        * If we have two threads using the same file descriptor, they could
-        * both enter this function, both notice that the structure hasn't
-        * been allocated yet and go ahead allocating it in parallel, but
-        * only one of them must survive and be shared otherwise we'd leak
-        * memory with a dangling notifier callback.
-        */
-       spin_lock(&file->f_lock);
-       if (!file->private_data) {
-               file->private_data = poll;
-       } else {
-               /* someone else raced ahead of us */
-               vcs_poll_data_free(poll);
-               poll = file->private_data;
-       }
-       spin_unlock(&file->f_lock);
-
-       return poll;
-}
-
-static int
-vcs_size(struct inode *inode)
-{
-       int size;
-       int minor = iminor(inode);
-       int currcons = minor & 127;
-       struct vc_data *vc;
-
-       if (currcons == 0)
-               currcons = fg_console;
-       else
-               currcons--;
-       if (!vc_cons_allocated(currcons))
-               return -ENXIO;
-       vc = vc_cons[currcons].d;
-
-       size = vc->vc_rows * vc->vc_cols;
-
-       if (minor & 128)
-               size = 2*size + HEADER_SIZE;
-       return size;
-}
-
-static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
-{
-       int size;
-
-       mutex_lock(&con_buf_mtx);
-       size = vcs_size(file->f_path.dentry->d_inode);
-       switch (orig) {
-               default:
-                       mutex_unlock(&con_buf_mtx);
-                       return -EINVAL;
-               case 2:
-                       offset += size;
-                       break;
-               case 1:
-                       offset += file->f_pos;
-               case 0:
-                       break;
-       }
-       if (offset < 0 || offset > size) {
-               mutex_unlock(&con_buf_mtx);
-               return -EINVAL;
-       }
-       file->f_pos = offset;
-       mutex_unlock(&con_buf_mtx);
-       return file->f_pos;
-}
-
-
-static ssize_t
-vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
-{
-       struct inode *inode = file->f_path.dentry->d_inode;
-       unsigned int currcons = iminor(inode);
-       struct vc_data *vc;
-       struct vcs_poll_data *poll;
-       long pos;
-       long viewed, attr, read;
-       int col, maxcol;
-       unsigned short *org = NULL;
-       ssize_t ret;
-
-       mutex_lock(&con_buf_mtx);
-
-       pos = *ppos;
-
-       /* Select the proper current console and verify
-        * sanity of the situation under the console lock.
-        */
-       acquire_console_sem();
-
-       attr = (currcons & 128);
-       currcons = (currcons & 127);
-       if (currcons == 0) {
-               currcons = fg_console;
-               viewed = 1;
-       } else {
-               currcons--;
-               viewed = 0;
-       }
-       ret = -ENXIO;
-       if (!vc_cons_allocated(currcons))
-               goto unlock_out;
-       vc = vc_cons[currcons].d;
-
-       ret = -EINVAL;
-       if (pos < 0)
-               goto unlock_out;
-       poll = file->private_data;
-       if (count && poll)
-               poll->seen_last_update = true;
-       read = 0;
-       ret = 0;
-       while (count) {
-               char *con_buf0, *con_buf_start;
-               long this_round, size;
-               ssize_t orig_count;
-               long p = pos;
-
-               /* Check whether we are above size each round,
-                * as copy_to_user at the end of this loop
-                * could sleep.
-                */
-               size = vcs_size(inode);
-               if (pos >= size)
-                       break;
-               if (count > size - pos)
-                       count = size - pos;
-
-               this_round = count;
-               if (this_round > CON_BUF_SIZE)
-                       this_round = CON_BUF_SIZE;
-
-               /* Perform the whole read into the local con_buf.
-                * Then we can drop the console spinlock and safely
-                * attempt to move it to userspace.
-                */
-
-               con_buf_start = con_buf0 = con_buf;
-               orig_count = this_round;
-               maxcol = vc->vc_cols;
-               if (!attr) {
-                       org = screen_pos(vc, p, viewed);
-                       col = p % maxcol;
-                       p += maxcol - col;
-                       while (this_round-- > 0) {
-                               *con_buf0++ = (vcs_scr_readw(vc, org++) & 0xff);
-                               if (++col == maxcol) {
-                                       org = screen_pos(vc, p, viewed);
-                                       col = 0;
-                                       p += maxcol;
-                               }
-                       }
-               } else {
-                       if (p < HEADER_SIZE) {
-                               size_t tmp_count;
-
-                               con_buf0[0] = (char)vc->vc_rows;
-                               con_buf0[1] = (char)vc->vc_cols;
-                               getconsxy(vc, con_buf0 + 2);
-
-                               con_buf_start += p;
-                               this_round += p;
-                               if (this_round > CON_BUF_SIZE) {
-                                       this_round = CON_BUF_SIZE;
-                                       orig_count = this_round - p;
-                               }
-
-                               tmp_count = HEADER_SIZE;
-                               if (tmp_count > this_round)
-                                       tmp_count = this_round;
-
-                               /* Advance state pointers and move on. */
-                               this_round -= tmp_count;
-                               p = HEADER_SIZE;
-                               con_buf0 = con_buf + HEADER_SIZE;
-                               /* If this_round >= 0, then p is even... */
-                       } else if (p & 1) {
-                               /* Skip first byte for output if start address is odd
-                                * Update region sizes up/down depending on free
-                                * space in buffer.
-                                */
-                               con_buf_start++;
-                               if (this_round < CON_BUF_SIZE)
-                                       this_round++;
-                               else
-                                       orig_count--;
-                       }
-                       if (this_round > 0) {
-                               unsigned short *tmp_buf = (unsigned short *)con_buf0;
-
-                               p -= HEADER_SIZE;
-                               p /= 2;
-                               col = p % maxcol;
-
-                               org = screen_pos(vc, p, viewed);
-                               p += maxcol - col;
-
-                               /* Buffer has even length, so we can always copy
-                                * character + attribute. We do not copy last byte
-                                * to userspace if this_round is odd.
-                                */
-                               this_round = (this_round + 1) >> 1;
-
-                               while (this_round) {
-                                       *tmp_buf++ = vcs_scr_readw(vc, org++);
-                                       this_round --;
-                                       if (++col == maxcol) {
-                                               org = screen_pos(vc, p, viewed);
-                                               col = 0;
-                                               p += maxcol;
-                                       }
-                               }
-                       }
-               }
-
-               /* Finally, release the console semaphore while we push
-                * all the data to userspace from our temporary buffer.
-                *
-                * AKPM: Even though it's a semaphore, we should drop it because
-                * the pagefault handling code may want to call printk().
-                */
-
-               release_console_sem();
-               ret = copy_to_user(buf, con_buf_start, orig_count);
-               acquire_console_sem();
-
-               if (ret) {
-                       read += (orig_count - ret);
-                       ret = -EFAULT;
-                       break;
-               }
-               buf += orig_count;
-               pos += orig_count;
-               read += orig_count;
-               count -= orig_count;
-       }
-       *ppos += read;
-       if (read)
-               ret = read;
-unlock_out:
-       release_console_sem();
-       mutex_unlock(&con_buf_mtx);
-       return ret;
-}
-
-static ssize_t
-vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
-{
-       struct inode *inode = file->f_path.dentry->d_inode;
-       unsigned int currcons = iminor(inode);
-       struct vc_data *vc;
-       long pos;
-       long viewed, attr, size, written;
-       char *con_buf0;
-       int col, maxcol;
-       u16 *org0 = NULL, *org = NULL;
-       size_t ret;
-
-       mutex_lock(&con_buf_mtx);
-
-       pos = *ppos;
-
-       /* Select the proper current console and verify
-        * sanity of the situation under the console lock.
-        */
-       acquire_console_sem();
-
-       attr = (currcons & 128);
-       currcons = (currcons & 127);
-
-       if (currcons == 0) {
-               currcons = fg_console;
-               viewed = 1;
-       } else {
-               currcons--;
-               viewed = 0;
-       }
-       ret = -ENXIO;
-       if (!vc_cons_allocated(currcons))
-               goto unlock_out;
-       vc = vc_cons[currcons].d;
-
-       size = vcs_size(inode);
-       ret = -EINVAL;
-       if (pos < 0 || pos > size)
-               goto unlock_out;
-       if (count > size - pos)
-               count = size - pos;
-       written = 0;
-       while (count) {
-               long this_round = count;
-               size_t orig_count;
-               long p;
-
-               if (this_round > CON_BUF_SIZE)
-                       this_round = CON_BUF_SIZE;
-
-               /* Temporarily drop the console lock so that we can read
-                * in the write data from userspace safely.
-                */
-               release_console_sem();
-               ret = copy_from_user(con_buf, buf, this_round);
-               acquire_console_sem();
-
-               if (ret) {
-                       this_round -= ret;
-                       if (!this_round) {
-                               /* Abort loop if no data were copied. Otherwise
-                                * fail with -EFAULT.
-                                */
-                               if (written)
-                                       break;
-                               ret = -EFAULT;
-                               goto unlock_out;
-                       }
-               }
-
-               /* The vcs_size might have changed while we slept to grab
-                * the user buffer, so recheck.
-                * Return data written up to now on failure.
-                */
-               size = vcs_size(inode);
-               if (pos >= size)
-                       break;
-               if (this_round > size - pos)
-                       this_round = size - pos;
-
-               /* OK, now actually push the write to the console
-                * under the lock using the local kernel buffer.
-                */
-
-               con_buf0 = con_buf;
-               orig_count = this_round;
-               maxcol = vc->vc_cols;
-               p = pos;
-               if (!attr) {
-                       org0 = org = screen_pos(vc, p, viewed);
-                       col = p % maxcol;
-                       p += maxcol - col;
-
-                       while (this_round > 0) {
-                               unsigned char c = *con_buf0++;
-
-                               this_round--;
-                               vcs_scr_writew(vc,
-                                              (vcs_scr_readw(vc, org) & 0xff00) | c, org);
-                               org++;
-                               if (++col == maxcol) {
-                                       org = screen_pos(vc, p, viewed);
-                                       col = 0;
-                                       p += maxcol;
-                               }
-                       }
-               } else {
-                       if (p < HEADER_SIZE) {
-                               char header[HEADER_SIZE];
-
-                               getconsxy(vc, header + 2);
-                               while (p < HEADER_SIZE && this_round > 0) {
-                                       this_round--;
-                                       header[p++] = *con_buf0++;
-                               }
-                               if (!viewed)
-                                       putconsxy(vc, header + 2);
-                       }
-                       p -= HEADER_SIZE;
-                       col = (p/2) % maxcol;
-                       if (this_round > 0) {
-                               org0 = org = screen_pos(vc, p/2, viewed);
-                               if ((p & 1) && this_round > 0) {
-                                       char c;
-
-                                       this_round--;
-                                       c = *con_buf0++;
-#ifdef __BIG_ENDIAN
-                                       vcs_scr_writew(vc, c |
-                                            (vcs_scr_readw(vc, org) & 0xff00), org);
-#else
-                                       vcs_scr_writew(vc, (c << 8) |
-                                            (vcs_scr_readw(vc, org) & 0xff), org);
-#endif
-                                       org++;
-                                       p++;
-                                       if (++col == maxcol) {
-                                               org = screen_pos(vc, p/2, viewed);
-                                               col = 0;
-                                       }
-                               }
-                               p /= 2;
-                               p += maxcol - col;
-                       }
-                       while (this_round > 1) {
-                               unsigned short w;
-
-                               w = get_unaligned(((unsigned short *)con_buf0));
-                               vcs_scr_writew(vc, w, org++);
-                               con_buf0 += 2;
-                               this_round -= 2;
-                               if (++col == maxcol) {
-                                       org = screen_pos(vc, p, viewed);
-                                       col = 0;
-                                       p += maxcol;
-                               }
-                       }
-                       if (this_round > 0) {
-                               unsigned char c;
-
-                               c = *con_buf0++;
-#ifdef __BIG_ENDIAN
-                               vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff) | (c << 8), org);
-#else
-                               vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff00) | c, org);
-#endif
-                       }
-               }
-               count -= orig_count;
-               written += orig_count;
-               buf += orig_count;
-               pos += orig_count;
-               if (org0)
-                       update_region(vc, (unsigned long)(org0), org - org0);
-       }
-       *ppos += written;
-       ret = written;
-       if (written)
-               vcs_scr_updated(vc);
-
-unlock_out:
-       release_console_sem();
-
-       mutex_unlock(&con_buf_mtx);
-
-       return ret;
-}
-
-static unsigned int
-vcs_poll(struct file *file, poll_table *wait)
-{
-       struct vcs_poll_data *poll = vcs_poll_data_get(file);
-       int ret = 0;
-
-       if (poll) {
-               poll_wait(file, &poll->waitq, wait);
-               if (!poll->seen_last_update)
-                       ret = POLLIN | POLLRDNORM;
-       }
-       return ret;
-}
-
-static int
-vcs_fasync(int fd, struct file *file, int on)
-{
-       struct vcs_poll_data *poll = file->private_data;
-
-       if (!poll) {
-               /* don't allocate anything if all we want is disable fasync */
-               if (!on)
-                       return 0;
-               poll = vcs_poll_data_get(file);
-               if (!poll)
-                       return -ENOMEM;
-       }
-
-       return fasync_helper(fd, file, on, &poll->fasync);
-}
-
-static int
-vcs_open(struct inode *inode, struct file *filp)
-{
-       unsigned int currcons = iminor(inode) & 127;
-       int ret = 0;
-       
-       tty_lock();
-       if(currcons && !vc_cons_allocated(currcons-1))
-               ret = -ENXIO;
-       tty_unlock();
-       return ret;
-}
-
-static int vcs_release(struct inode *inode, struct file *file)
-{
-       struct vcs_poll_data *poll = file->private_data;
-
-       if (poll)
-               vcs_poll_data_free(poll);
-       return 0;
-}
-
-static const struct file_operations vcs_fops = {
-       .llseek         = vcs_lseek,
-       .read           = vcs_read,
-       .write          = vcs_write,
-       .poll           = vcs_poll,
-       .fasync         = vcs_fasync,
-       .open           = vcs_open,
-       .release        = vcs_release,
-};
-
-static struct class *vc_class;
-
-void vcs_make_sysfs(int index)
-{
-       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL,
-                     "vcs%u", index + 1);
-       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL,
-                     "vcsa%u", index + 1);
-}
-
-void vcs_remove_sysfs(int index)
-{
-       device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1));
-       device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129));
-}
-
-int __init vcs_init(void)
-{
-       unsigned int i;
-
-       if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops))
-               panic("unable to get major %d for vcs device", VCS_MAJOR);
-       vc_class = class_create(THIS_MODULE, "vc");
-
-       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
-       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
-       for (i = 0; i < MIN_NR_CONSOLES; i++)
-               vcs_make_sysfs(i);
-       return 0;
-}
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
deleted file mode 100644 (file)
index a8ec48e..0000000
+++ /dev/null
@@ -1,4209 +0,0 @@
-/*
- *  linux/drivers/char/vt.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-/*
- * Hopefully this will be a rather complete VT102 implementation.
- *
- * Beeping thanks to John T Kohl.
- *
- * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
- *   Chars, and VT100 enhancements by Peter MacDonald.
- *
- * Copy and paste function by Andrew Haylett,
- *   some enhancements by Alessandro Rubini.
- *
- * Code to check for different video-cards mostly by Galen Hunt,
- * <g-hunt@ee.utah.edu>
- *
- * Rudimentary ISO 10646/Unicode/UTF-8 character set support by
- * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>.
- *
- * Dynamic allocation of consoles, aeb@cwi.nl, May 1994
- * Resizing of consoles, aeb, 940926
- *
- * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
- * <poe@daimi.aau.dk>
- *
- * User-defined bell sound, new setterm control sequences and printk
- * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95
- *
- * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
- *
- * Merge with the abstract console driver by Geert Uytterhoeven
- * <geert@linux-m68k.org>, Jan 1997.
- *
- *   Original m68k console driver modifications by
- *
- *     - Arno Griffioen <arno@usn.nl>
- *     - David Carter <carter@cs.bris.ac.uk>
- * 
- *   The abstract console driver provides a generic interface for a text
- *   console. It supports VGA text mode, frame buffer based graphical consoles
- *   and special graphics processors that are only accessible through some
- *   registers (e.g. a TMS340x0 GSP).
- *
- *   The interface to the hardware is specified using a special structure
- *   (struct consw) which contains function pointers to console operations
- *   (see <linux/console.h> for more information).
- *
- * Support for changeable cursor shape
- * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997
- *
- * Ported to i386 and con_scrolldelta fixed
- * by Emmanuel Marty <core@ggi-project.org>, April 1998
- *
- * Resurrected character buffers in videoram plus lots of other trickery
- * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
- *
- * Removed old-style timers, introduced console_timer, made timer
- * deletion SMP-safe.  17Jun00, Andrew Morton
- *
- * Removed console_lock, enabled interrupts across all console operations
- * 13 March 2001, Andrew Morton
- *
- * Fixed UTF-8 mode so alternate charset modes always work according
- * to control sequences interpreted in do_con_trol function
- * preserving backward VT100 semigraphics compatibility,
- * malformed UTF sequences represented as sequences of replacement glyphs,
- * original codes or '?' as a last resort if replacement glyph is undefined
- * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/kd.h>
-#include <linux/slab.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-#include <linux/smp_lock.h>
-#include <linux/tiocl.h>
-#include <linux/kbd_kern.h>
-#include <linux/consolemap.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/pm.h>
-#include <linux/font.h>
-#include <linux/bitops.h>
-#include <linux/notifier.h>
-#include <linux/device.h>
-#include <linux/io.h>
-#include <asm/system.h>
-#include <linux/uaccess.h>
-#include <linux/kdb.h>
-#include <linux/ctype.h>
-
-#define MAX_NR_CON_DRIVER 16
-
-#define CON_DRIVER_FLAG_MODULE 1
-#define CON_DRIVER_FLAG_INIT   2
-#define CON_DRIVER_FLAG_ATTR   4
-
-struct con_driver {
-       const struct consw *con;
-       const char *desc;
-       struct device *dev;
-       int node;
-       int first;
-       int last;
-       int flag;
-};
-
-static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER];
-const struct consw *conswitchp;
-
-/* A bitmap for codes <32. A bit of 1 indicates that the code
- * corresponding to that bit number invokes some special action
- * (such as cursor movement) and should not be displayed as a
- * glyph unless the disp_ctrl mode is explicitly enabled.
- */
-#define CTRL_ACTION 0x0d00ff81
-#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */
-
-/*
- * Here is the default bell parameters: 750HZ, 1/8th of a second
- */
-#define DEFAULT_BELL_PITCH     750
-#define DEFAULT_BELL_DURATION  (HZ/8)
-
-struct vc vc_cons [MAX_NR_CONSOLES];
-
-#ifndef VT_SINGLE_DRIVER
-static const struct consw *con_driver_map[MAX_NR_CONSOLES];
-#endif
-
-static int con_open(struct tty_struct *, struct file *);
-static void vc_init(struct vc_data *vc, unsigned int rows,
-                   unsigned int cols, int do_clear);
-static void gotoxy(struct vc_data *vc, int new_x, int new_y);
-static void save_cur(struct vc_data *vc);
-static void reset_terminal(struct vc_data *vc, int do_clear);
-static void con_flush_chars(struct tty_struct *tty);
-static int set_vesa_blanking(char __user *p);
-static void set_cursor(struct vc_data *vc);
-static void hide_cursor(struct vc_data *vc);
-static void console_callback(struct work_struct *ignored);
-static void blank_screen_t(unsigned long dummy);
-static void set_palette(struct vc_data *vc);
-
-static int printable;          /* Is console ready for printing? */
-int default_utf8 = true;
-module_param(default_utf8, int, S_IRUGO | S_IWUSR);
-int global_cursor_default = -1;
-module_param(global_cursor_default, int, S_IRUGO | S_IWUSR);
-
-static int cur_default = CUR_DEFAULT;
-module_param(cur_default, int, S_IRUGO | S_IWUSR);
-
-/*
- * ignore_poke: don't unblank the screen when things are typed.  This is
- * mainly for the privacy of braille terminal users.
- */
-static int ignore_poke;
-
-int do_poke_blanked_console;
-int console_blanked;
-
-static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
-static int vesa_off_interval;
-static int blankinterval = 10*60;
-core_param(consoleblank, blankinterval, int, 0444);
-
-static DECLARE_WORK(console_work, console_callback);
-
-/*
- * fg_console is the current virtual console,
- * last_console is the last used one,
- * want_console is the console we want to switch to,
- * saved_* variants are for save/restore around kernel debugger enter/leave
- */
-int fg_console;
-int last_console;
-int want_console = -1;
-static int saved_fg_console;
-static int saved_last_console;
-static int saved_want_console;
-static int saved_vc_mode;
-static int saved_console_blanked;
-
-/*
- * For each existing display, we have a pointer to console currently visible
- * on that display, allowing consoles other than fg_console to be refreshed
- * appropriately. Unless the low-level driver supplies its own display_fg
- * variable, we use this one for the "master display".
- */
-static struct vc_data *master_display_fg;
-
-/*
- * Unfortunately, we need to delay tty echo when we're currently writing to the
- * console since the code is (and always was) not re-entrant, so we schedule
- * all flip requests to process context with schedule-task() and run it from
- * console_callback().
- */
-
-/*
- * For the same reason, we defer scrollback to the console callback.
- */
-static int scrollback_delta;
-
-/*
- * Hook so that the power management routines can (un)blank
- * the console on our behalf.
- */
-int (*console_blank_hook)(int);
-
-static DEFINE_TIMER(console_timer, blank_screen_t, 0, 0);
-static int blank_state;
-static int blank_timer_expired;
-enum {
-       blank_off = 0,
-       blank_normal_wait,
-       blank_vesa_wait,
-};
-
-/*
- * Notifier list for console events.
- */
-static ATOMIC_NOTIFIER_HEAD(vt_notifier_list);
-
-int register_vt_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_register(&vt_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(register_vt_notifier);
-
-int unregister_vt_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_unregister(&vt_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_vt_notifier);
-
-static void notify_write(struct vc_data *vc, unsigned int unicode)
-{
-       struct vt_notifier_param param = { .vc = vc, unicode = unicode };
-       atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, &param);
-}
-
-static void notify_update(struct vc_data *vc)
-{
-       struct vt_notifier_param param = { .vc = vc };
-       atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, &param);
-}
-/*
- *     Low-Level Functions
- */
-
-#define IS_FG(vc)      ((vc)->vc_num == fg_console)
-
-#ifdef VT_BUF_VRAM_ONLY
-#define DO_UPDATE(vc)  0
-#else
-#define DO_UPDATE(vc)  (CON_IS_VISIBLE(vc) && !console_blanked)
-#endif
-
-static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
-{
-       unsigned short *p;
-       
-       if (!viewed)
-               p = (unsigned short *)(vc->vc_origin + offset);
-       else if (!vc->vc_sw->con_screen_pos)
-               p = (unsigned short *)(vc->vc_visible_origin + offset);
-       else
-               p = vc->vc_sw->con_screen_pos(vc, offset);
-       return p;
-}
-
-/* Called  from the keyboard irq path.. */
-static inline void scrolldelta(int lines)
-{
-       /* FIXME */
-       /* scrolldelta needs some kind of consistency lock, but the BKL was
-          and still is not protecting versus the scheduled back end */
-       scrollback_delta += lines;
-       schedule_console_callback();
-}
-
-void schedule_console_callback(void)
-{
-       schedule_work(&console_work);
-}
-
-static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
-{
-       unsigned short *d, *s;
-
-       if (t+nr >= b)
-               nr = b - t - 1;
-       if (b > vc->vc_rows || t >= b || nr < 1)
-               return;
-       if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr))
-               return;
-       d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
-       s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
-       scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
-       scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
-                   vc->vc_size_row * nr);
-}
-
-static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
-{
-       unsigned short *s;
-       unsigned int step;
-
-       if (t+nr >= b)
-               nr = b - t - 1;
-       if (b > vc->vc_rows || t >= b || nr < 1)
-               return;
-       if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr))
-               return;
-       s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
-       step = vc->vc_cols * nr;
-       scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
-       scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
-}
-
-static void do_update_region(struct vc_data *vc, unsigned long start, int count)
-{
-#ifndef VT_BUF_VRAM_ONLY
-       unsigned int xx, yy, offset;
-       u16 *p;
-
-       p = (u16 *) start;
-       if (!vc->vc_sw->con_getxy) {
-               offset = (start - vc->vc_origin) / 2;
-               xx = offset % vc->vc_cols;
-               yy = offset / vc->vc_cols;
-       } else {
-               int nxx, nyy;
-               start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy);
-               xx = nxx; yy = nyy;
-       }
-       for(;;) {
-               u16 attrib = scr_readw(p) & 0xff00;
-               int startx = xx;
-               u16 *q = p;
-               while (xx < vc->vc_cols && count) {
-                       if (attrib != (scr_readw(p) & 0xff00)) {
-                               if (p > q)
-                                       vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
-                               startx = xx;
-                               q = p;
-                               attrib = scr_readw(p) & 0xff00;
-                       }
-                       p++;
-                       xx++;
-                       count--;
-               }
-               if (p > q)
-                       vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
-               if (!count)
-                       break;
-               xx = 0;
-               yy++;
-               if (vc->vc_sw->con_getxy) {
-                       p = (u16 *)start;
-                       start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
-               }
-       }
-#endif
-}
-
-void update_region(struct vc_data *vc, unsigned long start, int count)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (DO_UPDATE(vc)) {
-               hide_cursor(vc);
-               do_update_region(vc, start, count);
-               set_cursor(vc);
-       }
-}
-
-/* Structure of attributes is hardware-dependent */
-
-static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
-    u8 _underline, u8 _reverse, u8 _italic)
-{
-       if (vc->vc_sw->con_build_attr)
-               return vc->vc_sw->con_build_attr(vc, _color, _intensity,
-                      _blink, _underline, _reverse, _italic);
-
-#ifndef VT_BUF_VRAM_ONLY
-/*
- * ++roman: I completely changed the attribute format for monochrome
- * mode (!can_do_color). The formerly used MDA (monochrome display
- * adapter) format didn't allow the combination of certain effects.
- * Now the attribute is just a bit vector:
- *  Bit 0..1: intensity (0..2)
- *  Bit 2   : underline
- *  Bit 3   : reverse
- *  Bit 7   : blink
- */
-       {
-       u8 a = _color;
-       if (!vc->vc_can_do_color)
-               return _intensity |
-                      (_italic ? 2 : 0) |
-                      (_underline ? 4 : 0) |
-                      (_reverse ? 8 : 0) |
-                      (_blink ? 0x80 : 0);
-       if (_italic)
-               a = (a & 0xF0) | vc->vc_itcolor;
-       else if (_underline)
-               a = (a & 0xf0) | vc->vc_ulcolor;
-       else if (_intensity == 0)
-               a = (a & 0xf0) | vc->vc_ulcolor;
-       if (_reverse)
-               a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
-       if (_blink)
-               a ^= 0x80;
-       if (_intensity == 2)
-               a ^= 0x08;
-       if (vc->vc_hi_font_mask == 0x100)
-               a <<= 1;
-       return a;
-       }
-#else
-       return 0;
-#endif
-}
-
-static void update_attr(struct vc_data *vc)
-{
-       vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity,
-                     vc->vc_blink, vc->vc_underline,
-                     vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
-       vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
-}
-
-/* Note: inverting the screen twice should revert to the original state */
-void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
-{
-       unsigned short *p;
-
-       WARN_CONSOLE_UNLOCKED();
-
-       count /= 2;
-       p = screenpos(vc, offset, viewed);
-       if (vc->vc_sw->con_invert_region)
-               vc->vc_sw->con_invert_region(vc, p, count);
-#ifndef VT_BUF_VRAM_ONLY
-       else {
-               u16 *q = p;
-               int cnt = count;
-               u16 a;
-
-               if (!vc->vc_can_do_color) {
-                       while (cnt--) {
-                           a = scr_readw(q);
-                           a ^= 0x0800;
-                           scr_writew(a, q);
-                           q++;
-                       }
-               } else if (vc->vc_hi_font_mask == 0x100) {
-                       while (cnt--) {
-                               a = scr_readw(q);
-                               a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
-                               scr_writew(a, q);
-                               q++;
-                       }
-               } else {
-                       while (cnt--) {
-                               a = scr_readw(q);
-                               a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
-                               scr_writew(a, q);
-                               q++;
-                       }
-               }
-       }
-#endif
-       if (DO_UPDATE(vc))
-               do_update_region(vc, (unsigned long) p, count);
-}
-
-/* used by selection: complement pointer position */
-void complement_pos(struct vc_data *vc, int offset)
-{
-       static int old_offset = -1;
-       static unsigned short old;
-       static unsigned short oldx, oldy;
-
-       WARN_CONSOLE_UNLOCKED();
-
-       if (old_offset != -1 && old_offset >= 0 &&
-           old_offset < vc->vc_screenbuf_size) {
-               scr_writew(old, screenpos(vc, old_offset, 1));
-               if (DO_UPDATE(vc))
-                       vc->vc_sw->con_putc(vc, old, oldy, oldx);
-       }
-
-       old_offset = offset;
-
-       if (offset != -1 && offset >= 0 &&
-           offset < vc->vc_screenbuf_size) {
-               unsigned short new;
-               unsigned short *p;
-               p = screenpos(vc, offset, 1);
-               old = scr_readw(p);
-               new = old ^ vc->vc_complement_mask;
-               scr_writew(new, p);
-               if (DO_UPDATE(vc)) {
-                       oldx = (offset >> 1) % vc->vc_cols;
-                       oldy = (offset >> 1) / vc->vc_cols;
-                       vc->vc_sw->con_putc(vc, new, oldy, oldx);
-               }
-       }
-
-}
-
-static void insert_char(struct vc_data *vc, unsigned int nr)
-{
-       unsigned short *p, *q = (unsigned short *)vc->vc_pos;
-
-       p = q + vc->vc_cols - nr - vc->vc_x;
-       while (--p >= q)
-               scr_writew(scr_readw(p), p + nr);
-       scr_memsetw(q, vc->vc_video_erase_char, nr * 2);
-       vc->vc_need_wrap = 0;
-       if (DO_UPDATE(vc)) {
-               unsigned short oldattr = vc->vc_attr;
-               vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1,
-                                    vc->vc_cols - vc->vc_x - nr);
-               vc->vc_attr = vc->vc_video_erase_char >> 8;
-               while (nr--)
-                       vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr);
-               vc->vc_attr = oldattr;
-       }
-}
-
-static void delete_char(struct vc_data *vc, unsigned int nr)
-{
-       unsigned int i = vc->vc_x;
-       unsigned short *p = (unsigned short *)vc->vc_pos;
-
-       while (++i <= vc->vc_cols - nr) {
-               scr_writew(scr_readw(p+nr), p);
-               p++;
-       }
-       scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
-       vc->vc_need_wrap = 0;
-       if (DO_UPDATE(vc)) {
-               unsigned short oldattr = vc->vc_attr;
-               vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1,
-                                    vc->vc_cols - vc->vc_x - nr);
-               vc->vc_attr = vc->vc_video_erase_char >> 8;
-               while (nr--)
-                       vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y,
-                                    vc->vc_cols - 1 - nr);
-               vc->vc_attr = oldattr;
-       }
-}
-
-static int softcursor_original;
-
-static void add_softcursor(struct vc_data *vc)
-{
-       int i = scr_readw((u16 *) vc->vc_pos);
-       u32 type = vc->vc_cursor_type;
-
-       if (! (type & 0x10)) return;
-       if (softcursor_original != -1) return;
-       softcursor_original = i;
-       i |= ((type >> 8) & 0xff00 );
-       i ^= ((type) & 0xff00 );
-       if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
-       if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
-       scr_writew(i, (u16 *) vc->vc_pos);
-       if (DO_UPDATE(vc))
-               vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x);
-}
-
-static void hide_softcursor(struct vc_data *vc)
-{
-       if (softcursor_original != -1) {
-               scr_writew(softcursor_original, (u16 *)vc->vc_pos);
-               if (DO_UPDATE(vc))
-                       vc->vc_sw->con_putc(vc, softcursor_original,
-                                       vc->vc_y, vc->vc_x);
-               softcursor_original = -1;
-       }
-}
-
-static void hide_cursor(struct vc_data *vc)
-{
-       if (vc == sel_cons)
-               clear_selection();
-       vc->vc_sw->con_cursor(vc, CM_ERASE);
-       hide_softcursor(vc);
-}
-
-static void set_cursor(struct vc_data *vc)
-{
-       if (!IS_FG(vc) || console_blanked ||
-           vc->vc_mode == KD_GRAPHICS)
-               return;
-       if (vc->vc_deccm) {
-               if (vc == sel_cons)
-                       clear_selection();
-               add_softcursor(vc);
-               if ((vc->vc_cursor_type & 0x0f) != 1)
-                       vc->vc_sw->con_cursor(vc, CM_DRAW);
-       } else
-               hide_cursor(vc);
-}
-
-static void set_origin(struct vc_data *vc)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (!CON_IS_VISIBLE(vc) ||
-           !vc->vc_sw->con_set_origin ||
-           !vc->vc_sw->con_set_origin(vc))
-               vc->vc_origin = (unsigned long)vc->vc_screenbuf;
-       vc->vc_visible_origin = vc->vc_origin;
-       vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
-       vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
-}
-
-static inline void save_screen(struct vc_data *vc)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (vc->vc_sw->con_save_screen)
-               vc->vc_sw->con_save_screen(vc);
-}
-
-/*
- *     Redrawing of screen
- */
-
-static void clear_buffer_attributes(struct vc_data *vc)
-{
-       unsigned short *p = (unsigned short *)vc->vc_origin;
-       int count = vc->vc_screenbuf_size / 2;
-       int mask = vc->vc_hi_font_mask | 0xff;
-
-       for (; count > 0; count--, p++) {
-               scr_writew((scr_readw(p)&mask) | (vc->vc_video_erase_char & ~mask), p);
-       }
-}
-
-void redraw_screen(struct vc_data *vc, int is_switch)
-{
-       int redraw = 0;
-
-       WARN_CONSOLE_UNLOCKED();
-
-       if (!vc) {
-               /* strange ... */
-               /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
-               return;
-       }
-
-       if (is_switch) {
-               struct vc_data *old_vc = vc_cons[fg_console].d;
-               if (old_vc == vc)
-                       return;
-               if (!CON_IS_VISIBLE(vc))
-                       redraw = 1;
-               *vc->vc_display_fg = vc;
-               fg_console = vc->vc_num;
-               hide_cursor(old_vc);
-               if (!CON_IS_VISIBLE(old_vc)) {
-                       save_screen(old_vc);
-                       set_origin(old_vc);
-               }
-       } else {
-               hide_cursor(vc);
-               redraw = 1;
-       }
-
-       if (redraw) {
-               int update;
-               int old_was_color = vc->vc_can_do_color;
-
-               set_origin(vc);
-               update = vc->vc_sw->con_switch(vc);
-               set_palette(vc);
-               /*
-                * If console changed from mono<->color, the best we can do
-                * is to clear the buffer attributes. As it currently stands,
-                * rebuilding new attributes from the old buffer is not doable
-                * without overly complex code.
-                */
-               if (old_was_color != vc->vc_can_do_color) {
-                       update_attr(vc);
-                       clear_buffer_attributes(vc);
-               }
-
-               /* Forcibly update if we're panicing */
-               if ((update && vc->vc_mode != KD_GRAPHICS) ||
-                   vt_force_oops_output(vc))
-                       do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
-       }
-       set_cursor(vc);
-       if (is_switch) {
-               set_leds();
-               compute_shiftstate();
-               notify_update(vc);
-       }
-}
-
-/*
- *     Allocation, freeing and resizing of VTs.
- */
-
-int vc_cons_allocated(unsigned int i)
-{
-       return (i < MAX_NR_CONSOLES && vc_cons[i].d);
-}
-
-static void visual_init(struct vc_data *vc, int num, int init)
-{
-       /* ++Geert: vc->vc_sw->con_init determines console size */
-       if (vc->vc_sw)
-               module_put(vc->vc_sw->owner);
-       vc->vc_sw = conswitchp;
-#ifndef VT_SINGLE_DRIVER
-       if (con_driver_map[num])
-               vc->vc_sw = con_driver_map[num];
-#endif
-       __module_get(vc->vc_sw->owner);
-       vc->vc_num = num;
-       vc->vc_display_fg = &master_display_fg;
-       vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
-       vc->vc_uni_pagedir = 0;
-       vc->vc_hi_font_mask = 0;
-       vc->vc_complement_mask = 0;
-       vc->vc_can_do_color = 0;
-       vc->vc_panic_force_write = false;
-       vc->vc_sw->con_init(vc, init);
-       if (!vc->vc_complement_mask)
-               vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
-       vc->vc_s_complement_mask = vc->vc_complement_mask;
-       vc->vc_size_row = vc->vc_cols << 1;
-       vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
-}
-
-int vc_allocate(unsigned int currcons) /* return 0 on success */
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (currcons >= MAX_NR_CONSOLES)
-               return -ENXIO;
-       if (!vc_cons[currcons].d) {
-           struct vc_data *vc;
-           struct vt_notifier_param param;
-
-           /* prevent users from taking too much memory */
-           if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
-             return -EPERM;
-
-           /* due to the granularity of kmalloc, we waste some memory here */
-           /* the alloc is done in two steps, to optimize the common situation
-              of a 25x80 console (structsize=216, screenbuf_size=4000) */
-           /* although the numbers above are not valid since long ago, the
-              point is still up-to-date and the comment still has its value
-              even if only as a historical artifact.  --mj, July 1998 */
-           param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
-           if (!vc)
-               return -ENOMEM;
-           vc_cons[currcons].d = vc;
-           tty_port_init(&vc->port);
-           INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
-           visual_init(vc, currcons, 1);
-           if (!*vc->vc_uni_pagedir_loc)
-               con_set_default_unimap(vc);
-           vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
-           if (!vc->vc_screenbuf) {
-               kfree(vc);
-               vc_cons[currcons].d = NULL;
-               return -ENOMEM;
-           }
-
-           /* If no drivers have overridden us and the user didn't pass a
-              boot option, default to displaying the cursor */
-           if (global_cursor_default == -1)
-                   global_cursor_default = 1;
-
-           vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
-           vcs_make_sysfs(currcons);
-           atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
-       }
-       return 0;
-}
-
-static inline int resize_screen(struct vc_data *vc, int width, int height,
-                               int user)
-{
-       /* Resizes the resolution of the display adapater */
-       int err = 0;
-
-       if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize)
-               err = vc->vc_sw->con_resize(vc, width, height, user);
-
-       return err;
-}
-
-/*
- * Change # of rows and columns (0 means unchanged/the size of fg_console)
- * [this is to be used together with some user program
- * like resize that changes the hardware videomode]
- */
-#define VC_RESIZE_MAXCOL (32767)
-#define VC_RESIZE_MAXROW (32767)
-
-/**
- *     vc_do_resize    -       resizing method for the tty
- *     @tty: tty being resized
- *     @real_tty: real tty (different to tty if a pty/tty pair)
- *     @vc: virtual console private data
- *     @cols: columns
- *     @lines: lines
- *
- *     Resize a virtual console, clipping according to the actual constraints.
- *     If the caller passes a tty structure then update the termios winsize
- *     information and perform any necessary signal handling.
- *
- *     Caller must hold the console semaphore. Takes the termios mutex and
- *     ctrl_lock of the tty IFF a tty is passed.
- */
-
-static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
-                               unsigned int cols, unsigned int lines)
-{
-       unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
-       unsigned long end;
-       unsigned int old_cols, old_rows, old_row_size, old_screen_size;
-       unsigned int new_cols, new_rows, new_row_size, new_screen_size;
-       unsigned int user;
-       unsigned short *newscreen;
-
-       WARN_CONSOLE_UNLOCKED();
-
-       if (!vc)
-               return -ENXIO;
-
-       user = vc->vc_resize_user;
-       vc->vc_resize_user = 0;
-
-       if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
-               return -EINVAL;
-
-       new_cols = (cols ? cols : vc->vc_cols);
-       new_rows = (lines ? lines : vc->vc_rows);
-       new_row_size = new_cols << 1;
-       new_screen_size = new_row_size * new_rows;
-
-       if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
-               return 0;
-
-       newscreen = kmalloc(new_screen_size, GFP_USER);
-       if (!newscreen)
-               return -ENOMEM;
-
-       old_rows = vc->vc_rows;
-       old_cols = vc->vc_cols;
-       old_row_size = vc->vc_size_row;
-       old_screen_size = vc->vc_screenbuf_size;
-
-       err = resize_screen(vc, new_cols, new_rows, user);
-       if (err) {
-               kfree(newscreen);
-               return err;
-       }
-
-       vc->vc_rows = new_rows;
-       vc->vc_cols = new_cols;
-       vc->vc_size_row = new_row_size;
-       vc->vc_screenbuf_size = new_screen_size;
-
-       rlth = min(old_row_size, new_row_size);
-       rrem = new_row_size - rlth;
-       old_origin = vc->vc_origin;
-       new_origin = (long) newscreen;
-       new_scr_end = new_origin + new_screen_size;
-
-       if (vc->vc_y > new_rows) {
-               if (old_rows - vc->vc_y < new_rows) {
-                       /*
-                        * Cursor near the bottom, copy contents from the
-                        * bottom of buffer
-                        */
-                       old_origin += (old_rows - new_rows) * old_row_size;
-               } else {
-                       /*
-                        * Cursor is in no man's land, copy 1/2 screenful
-                        * from the top and bottom of cursor position
-                        */
-                       old_origin += (vc->vc_y - new_rows/2) * old_row_size;
-               }
-       }
-
-       end = old_origin + old_row_size * min(old_rows, new_rows);
-
-       update_attr(vc);
-
-       while (old_origin < end) {
-               scr_memcpyw((unsigned short *) new_origin,
-                           (unsigned short *) old_origin, rlth);
-               if (rrem)
-                       scr_memsetw((void *)(new_origin + rlth),
-                                   vc->vc_video_erase_char, rrem);
-               old_origin += old_row_size;
-               new_origin += new_row_size;
-       }
-       if (new_scr_end > new_origin)
-               scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
-                           new_scr_end - new_origin);
-       kfree(vc->vc_screenbuf);
-       vc->vc_screenbuf = newscreen;
-       vc->vc_screenbuf_size = new_screen_size;
-       set_origin(vc);
-
-       /* do part of a reset_terminal() */
-       vc->vc_top = 0;
-       vc->vc_bottom = vc->vc_rows;
-       gotoxy(vc, vc->vc_x, vc->vc_y);
-       save_cur(vc);
-
-       if (tty) {
-               /* Rewrite the requested winsize data with the actual
-                  resulting sizes */
-               struct winsize ws;
-               memset(&ws, 0, sizeof(ws));
-               ws.ws_row = vc->vc_rows;
-               ws.ws_col = vc->vc_cols;
-               ws.ws_ypixel = vc->vc_scan_lines;
-               tty_do_resize(tty, &ws);
-       }
-
-       if (CON_IS_VISIBLE(vc))
-               update_screen(vc);
-       vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
-       return err;
-}
-
-/**
- *     vc_resize               -       resize a VT
- *     @vc: virtual console
- *     @cols: columns
- *     @rows: rows
- *
- *     Resize a virtual console as seen from the console end of things. We
- *     use the common vc_do_resize methods to update the structures. The
- *     caller must hold the console sem to protect console internals and
- *     vc->port.tty
- */
-
-int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
-{
-       return vc_do_resize(vc->port.tty, vc, cols, rows);
-}
-
-/**
- *     vt_resize               -       resize a VT
- *     @tty: tty to resize
- *     @ws: winsize attributes
- *
- *     Resize a virtual terminal. This is called by the tty layer as we
- *     register our own handler for resizing. The mutual helper does all
- *     the actual work.
- *
- *     Takes the console sem and the called methods then take the tty
- *     termios_mutex and the tty ctrl_lock in that order.
- */
-static int vt_resize(struct tty_struct *tty, struct winsize *ws)
-{
-       struct vc_data *vc = tty->driver_data;
-       int ret;
-
-       acquire_console_sem();
-       ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row);
-       release_console_sem();
-       return ret;
-}
-
-void vc_deallocate(unsigned int currcons)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (vc_cons_allocated(currcons)) {
-               struct vc_data *vc = vc_cons[currcons].d;
-               struct vt_notifier_param param = { .vc = vc };
-
-               atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param);
-               vcs_remove_sysfs(currcons);
-               vc->vc_sw->con_deinit(vc);
-               put_pid(vc->vt_pid);
-               module_put(vc->vc_sw->owner);
-               kfree(vc->vc_screenbuf);
-               if (currcons >= MIN_NR_CONSOLES)
-                       kfree(vc);
-               vc_cons[currcons].d = NULL;
-       }
-}
-
-/*
- *     VT102 emulator
- */
-
-#define set_kbd(vc, x) set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
-#define clr_kbd(vc, x) clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
-#define is_kbd(vc, x)  vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
-
-#define decarm         VC_REPEAT
-#define decckm         VC_CKMODE
-#define kbdapplic      VC_APPLIC
-#define lnm            VC_CRLF
-
-/*
- * this is what the terminal answers to a ESC-Z or csi0c query.
- */
-#define VT100ID "\033[?1;2c"
-#define VT102ID "\033[?6c"
-
-unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
-                                      8,12,10,14, 9,13,11,15 };
-
-/* the default colour table, for VGA+ colour systems */
-int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
-    0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
-int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
-    0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
-int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
-    0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
-
-module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR);
-module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR);
-module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR);
-
-/*
- * gotoxy() must verify all boundaries, because the arguments
- * might also be negative. If the given position is out of
- * bounds, the cursor is placed at the nearest margin.
- */
-static void gotoxy(struct vc_data *vc, int new_x, int new_y)
-{
-       int min_y, max_y;
-
-       if (new_x < 0)
-               vc->vc_x = 0;
-       else {
-               if (new_x >= vc->vc_cols)
-                       vc->vc_x = vc->vc_cols - 1;
-               else
-                       vc->vc_x = new_x;
-       }
-
-       if (vc->vc_decom) {
-               min_y = vc->vc_top;
-               max_y = vc->vc_bottom;
-       } else {
-               min_y = 0;
-               max_y = vc->vc_rows;
-       }
-       if (new_y < min_y)
-               vc->vc_y = min_y;
-       else if (new_y >= max_y)
-               vc->vc_y = max_y - 1;
-       else
-               vc->vc_y = new_y;
-       vc->vc_pos = vc->vc_origin + vc->vc_y * vc->vc_size_row + (vc->vc_x<<1);
-       vc->vc_need_wrap = 0;
-}
-
-/* for absolute user moves, when decom is set */
-static void gotoxay(struct vc_data *vc, int new_x, int new_y)
-{
-       gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y);
-}
-
-void scrollback(struct vc_data *vc, int lines)
-{
-       if (!lines)
-               lines = vc->vc_rows / 2;
-       scrolldelta(-lines);
-}
-
-void scrollfront(struct vc_data *vc, int lines)
-{
-       if (!lines)
-               lines = vc->vc_rows / 2;
-       scrolldelta(lines);
-}
-
-static void lf(struct vc_data *vc)
-{
-       /* don't scroll if above bottom of scrolling region, or
-        * if below scrolling region
-        */
-       if (vc->vc_y + 1 == vc->vc_bottom)
-               scrup(vc, vc->vc_top, vc->vc_bottom, 1);
-       else if (vc->vc_y < vc->vc_rows - 1) {
-               vc->vc_y++;
-               vc->vc_pos += vc->vc_size_row;
-       }
-       vc->vc_need_wrap = 0;
-       notify_write(vc, '\n');
-}
-
-static void ri(struct vc_data *vc)
-{
-       /* don't scroll if below top of scrolling region, or
-        * if above scrolling region
-        */
-       if (vc->vc_y == vc->vc_top)
-               scrdown(vc, vc->vc_top, vc->vc_bottom, 1);
-       else if (vc->vc_y > 0) {
-               vc->vc_y--;
-               vc->vc_pos -= vc->vc_size_row;
-       }
-       vc->vc_need_wrap = 0;
-}
-
-static inline void cr(struct vc_data *vc)
-{
-       vc->vc_pos -= vc->vc_x << 1;
-       vc->vc_need_wrap = vc->vc_x = 0;
-       notify_write(vc, '\r');
-}
-
-static inline void bs(struct vc_data *vc)
-{
-       if (vc->vc_x) {
-               vc->vc_pos -= 2;
-               vc->vc_x--;
-               vc->vc_need_wrap = 0;
-               notify_write(vc, '\b');
-       }
-}
-
-static inline void del(struct vc_data *vc)
-{
-       /* ignored */
-}
-
-static void csi_J(struct vc_data *vc, int vpar)
-{
-       unsigned int count;
-       unsigned short * start;
-
-       switch (vpar) {
-               case 0: /* erase from cursor to end of display */
-                       count = (vc->vc_scr_end - vc->vc_pos) >> 1;
-                       start = (unsigned short *)vc->vc_pos;
-                       if (DO_UPDATE(vc)) {
-                               /* do in two stages */
-                               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
-                                             vc->vc_cols - vc->vc_x);
-                               vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0,
-                                             vc->vc_rows - vc->vc_y - 1,
-                                             vc->vc_cols);
-                       }
-                       break;
-               case 1: /* erase from start to cursor */
-                       count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
-                       start = (unsigned short *)vc->vc_origin;
-                       if (DO_UPDATE(vc)) {
-                               /* do in two stages */
-                               vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y,
-                                             vc->vc_cols);
-                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
-                                             vc->vc_x + 1);
-                       }
-                       break;
-               case 2: /* erase whole display */
-                       count = vc->vc_cols * vc->vc_rows;
-                       start = (unsigned short *)vc->vc_origin;
-                       if (DO_UPDATE(vc))
-                               vc->vc_sw->con_clear(vc, 0, 0,
-                                             vc->vc_rows,
-                                             vc->vc_cols);
-                       break;
-               default:
-                       return;
-       }
-       scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
-       vc->vc_need_wrap = 0;
-}
-
-static void csi_K(struct vc_data *vc, int vpar)
-{
-       unsigned int count;
-       unsigned short * start;
-
-       switch (vpar) {
-               case 0: /* erase from cursor to end of line */
-                       count = vc->vc_cols - vc->vc_x;
-                       start = (unsigned short *)vc->vc_pos;
-                       if (DO_UPDATE(vc))
-                               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
-                                                    vc->vc_cols - vc->vc_x);
-                       break;
-               case 1: /* erase from start of line to cursor */
-                       start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
-                       count = vc->vc_x + 1;
-                       if (DO_UPDATE(vc))
-                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
-                                                    vc->vc_x + 1);
-                       break;
-               case 2: /* erase whole line */
-                       start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
-                       count = vc->vc_cols;
-                       if (DO_UPDATE(vc))
-                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
-                                             vc->vc_cols);
-                       break;
-               default:
-                       return;
-       }
-       scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
-       vc->vc_need_wrap = 0;
-}
-
-static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */
-{                                        /* not vt100? */
-       int count;
-
-       if (!vpar)
-               vpar++;
-       count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar;
-
-       scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
-       if (DO_UPDATE(vc))
-               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count);
-       vc->vc_need_wrap = 0;
-}
-
-static void default_attr(struct vc_data *vc)
-{
-       vc->vc_intensity = 1;
-       vc->vc_italic = 0;
-       vc->vc_underline = 0;
-       vc->vc_reverse = 0;
-       vc->vc_blink = 0;
-       vc->vc_color = vc->vc_def_color;
-}
-
-/* console_sem is held */
-static void csi_m(struct vc_data *vc)
-{
-       int i;
-
-       for (i = 0; i <= vc->vc_npar; i++)
-               switch (vc->vc_par[i]) {
-                       case 0: /* all attributes off */
-                               default_attr(vc);
-                               break;
-                       case 1:
-                               vc->vc_intensity = 2;
-                               break;
-                       case 2:
-                               vc->vc_intensity = 0;
-                               break;
-                       case 3:
-                               vc->vc_italic = 1;
-                               break;
-                       case 4:
-                               vc->vc_underline = 1;
-                               break;
-                       case 5:
-                               vc->vc_blink = 1;
-                               break;
-                       case 7:
-                               vc->vc_reverse = 1;
-                               break;
-                       case 10: /* ANSI X3.64-1979 (SCO-ish?)
-                                 * Select primary font, don't display
-                                 * control chars if defined, don't set
-                                 * bit 8 on output.
-                                 */
-                               vc->vc_translate = set_translate(vc->vc_charset == 0
-                                               ? vc->vc_G0_charset
-                                               : vc->vc_G1_charset, vc);
-                               vc->vc_disp_ctrl = 0;
-                               vc->vc_toggle_meta = 0;
-                               break;
-                       case 11: /* ANSI X3.64-1979 (SCO-ish?)
-                                 * Select first alternate font, lets
-                                 * chars < 32 be displayed as ROM chars.
-                                 */
-                               vc->vc_translate = set_translate(IBMPC_MAP, vc);
-                               vc->vc_disp_ctrl = 1;
-                               vc->vc_toggle_meta = 0;
-                               break;
-                       case 12: /* ANSI X3.64-1979 (SCO-ish?)
-                                 * Select second alternate font, toggle
-                                 * high bit before displaying as ROM char.
-                                 */
-                               vc->vc_translate = set_translate(IBMPC_MAP, vc);
-                               vc->vc_disp_ctrl = 1;
-                               vc->vc_toggle_meta = 1;
-                               break;
-                       case 21:
-                       case 22:
-                               vc->vc_intensity = 1;
-                               break;
-                       case 23:
-                               vc->vc_italic = 0;
-                               break;
-                       case 24:
-                               vc->vc_underline = 0;
-                               break;
-                       case 25:
-                               vc->vc_blink = 0;
-                               break;
-                       case 27:
-                               vc->vc_reverse = 0;
-                               break;
-                       case 38: /* ANSI X3.64-1979 (SCO-ish?)
-                                 * Enables underscore, white foreground
-                                 * with white underscore (Linux - use
-                                 * default foreground).
-                                 */
-                               vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
-                               vc->vc_underline = 1;
-                               break;
-                       case 39: /* ANSI X3.64-1979 (SCO-ish?)
-                                 * Disable underline option.
-                                 * Reset colour to default? It did this
-                                 * before...
-                                 */
-                               vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
-                               vc->vc_underline = 0;
-                               break;
-                       case 49:
-                               vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f);
-                               break;
-                       default:
-                               if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
-                                       vc->vc_color = color_table[vc->vc_par[i] - 30]
-                                               | (vc->vc_color & 0xf0);
-                               else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
-                                       vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
-                                               | (vc->vc_color & 0x0f);
-                               break;
-               }
-       update_attr(vc);
-}
-
-static void respond_string(const char *p, struct tty_struct *tty)
-{
-       while (*p) {
-               tty_insert_flip_char(tty, *p, 0);
-               p++;
-       }
-       con_schedule_flip(tty);
-}
-
-static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
-{
-       char buf[40];
-
-       sprintf(buf, "\033[%d;%dR", vc->vc_y + (vc->vc_decom ? vc->vc_top + 1 : 1), vc->vc_x + 1);
-       respond_string(buf, tty);
-}
-
-static inline void status_report(struct tty_struct *tty)
-{
-       respond_string("\033[0n", tty); /* Terminal ok */
-}
-
-static inline void respond_ID(struct tty_struct * tty)
-{
-       respond_string(VT102ID, tty);
-}
-
-void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry)
-{
-       char buf[8];
-
-       sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
-               (char)('!' + mry));
-       respond_string(buf, tty);
-}
-
-/* invoked via ioctl(TIOCLINUX) and through set_selection */
-int mouse_reporting(void)
-{
-       return vc_cons[fg_console].d->vc_report_mouse;
-}
-
-/* console_sem is held */
-static void set_mode(struct vc_data *vc, int on_off)
-{
-       int i;
-
-       for (i = 0; i <= vc->vc_npar; i++)
-               if (vc->vc_ques) {
-                       switch(vc->vc_par[i]) { /* DEC private modes set/reset */
-                       case 1:                 /* Cursor keys send ^[Ox/^[[x */
-                               if (on_off)
-                                       set_kbd(vc, decckm);
-                               else
-                                       clr_kbd(vc, decckm);
-                               break;
-                       case 3: /* 80/132 mode switch unimplemented */
-                               vc->vc_deccolm = on_off;
-#if 0
-                               vc_resize(deccolm ? 132 : 80, vc->vc_rows);
-                               /* this alone does not suffice; some user mode
-                                  utility has to change the hardware regs */
-#endif
-                               break;
-                       case 5:                 /* Inverted screen on/off */
-                               if (vc->vc_decscnm != on_off) {
-                                       vc->vc_decscnm = on_off;
-                                       invert_screen(vc, 0, vc->vc_screenbuf_size, 0);
-                                       update_attr(vc);
-                               }
-                               break;
-                       case 6:                 /* Origin relative/absolute */
-                               vc->vc_decom = on_off;
-                               gotoxay(vc, 0, 0);
-                               break;
-                       case 7:                 /* Autowrap on/off */
-                               vc->vc_decawm = on_off;
-                               break;
-                       case 8:                 /* Autorepeat on/off */
-                               if (on_off)
-                                       set_kbd(vc, decarm);
-                               else
-                                       clr_kbd(vc, decarm);
-                               break;
-                       case 9:
-                               vc->vc_report_mouse = on_off ? 1 : 0;
-                               break;
-                       case 25:                /* Cursor on/off */
-                               vc->vc_deccm = on_off;
-                               break;
-                       case 1000:
-                               vc->vc_report_mouse = on_off ? 2 : 0;
-                               break;
-                       }
-               } else {
-                       switch(vc->vc_par[i]) { /* ANSI modes set/reset */
-                       case 3:                 /* Monitor (display ctrls) */
-                               vc->vc_disp_ctrl = on_off;
-                               break;
-                       case 4:                 /* Insert Mode on/off */
-                               vc->vc_decim = on_off;
-                               break;
-                       case 20:                /* Lf, Enter == CrLf/Lf */
-                               if (on_off)
-                                       set_kbd(vc, lnm);
-                               else
-                                       clr_kbd(vc, lnm);
-                               break;
-                       }
-               }
-}
-
-/* console_sem is held */
-static void setterm_command(struct vc_data *vc)
-{
-       switch(vc->vc_par[0]) {
-               case 1: /* set color for underline mode */
-                       if (vc->vc_can_do_color &&
-                                       vc->vc_par[1] < 16) {
-                               vc->vc_ulcolor = color_table[vc->vc_par[1]];
-                               if (vc->vc_underline)
-                                       update_attr(vc);
-                       }
-                       break;
-               case 2: /* set color for half intensity mode */
-                       if (vc->vc_can_do_color &&
-                                       vc->vc_par[1] < 16) {
-                               vc->vc_halfcolor = color_table[vc->vc_par[1]];
-                               if (vc->vc_intensity == 0)
-                                       update_attr(vc);
-                       }
-                       break;
-               case 8: /* store colors as defaults */
-                       vc->vc_def_color = vc->vc_attr;
-                       if (vc->vc_hi_font_mask == 0x100)
-                               vc->vc_def_color >>= 1;
-                       default_attr(vc);
-                       update_attr(vc);
-                       break;
-               case 9: /* set blanking interval */
-                       blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60;
-                       poke_blanked_console();
-                       break;
-               case 10: /* set bell frequency in Hz */
-                       if (vc->vc_npar >= 1)
-                               vc->vc_bell_pitch = vc->vc_par[1];
-                       else
-                               vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
-                       break;
-               case 11: /* set bell duration in msec */
-                       if (vc->vc_npar >= 1)
-                               vc->vc_bell_duration = (vc->vc_par[1] < 2000) ?
-                                       vc->vc_par[1] * HZ / 1000 : 0;
-                       else
-                               vc->vc_bell_duration = DEFAULT_BELL_DURATION;
-                       break;
-               case 12: /* bring specified console to the front */
-                       if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1))
-                               set_console(vc->vc_par[1] - 1);
-                       break;
-               case 13: /* unblank the screen */
-                       poke_blanked_console();
-                       break;
-               case 14: /* set vesa powerdown interval */
-                       vesa_off_interval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ;
-                       break;
-               case 15: /* activate the previous console */
-                       set_console(last_console);
-                       break;
-       }
-}
-
-/* console_sem is held */
-static void csi_at(struct vc_data *vc, unsigned int nr)
-{
-       if (nr > vc->vc_cols - vc->vc_x)
-               nr = vc->vc_cols - vc->vc_x;
-       else if (!nr)
-               nr = 1;
-       insert_char(vc, nr);
-}
-
-/* console_sem is held */
-static void csi_L(struct vc_data *vc, unsigned int nr)
-{
-       if (nr > vc->vc_rows - vc->vc_y)
-               nr = vc->vc_rows - vc->vc_y;
-       else if (!nr)
-               nr = 1;
-       scrdown(vc, vc->vc_y, vc->vc_bottom, nr);
-       vc->vc_need_wrap = 0;
-}
-
-/* console_sem is held */
-static void csi_P(struct vc_data *vc, unsigned int nr)
-{
-       if (nr > vc->vc_cols - vc->vc_x)
-               nr = vc->vc_cols - vc->vc_x;
-       else if (!nr)
-               nr = 1;
-       delete_char(vc, nr);
-}
-
-/* console_sem is held */
-static void csi_M(struct vc_data *vc, unsigned int nr)
-{
-       if (nr > vc->vc_rows - vc->vc_y)
-               nr = vc->vc_rows - vc->vc_y;
-       else if (!nr)
-               nr=1;
-       scrup(vc, vc->vc_y, vc->vc_bottom, nr);
-       vc->vc_need_wrap = 0;
-}
-
-/* console_sem is held (except via vc_init->reset_terminal */
-static void save_cur(struct vc_data *vc)
-{
-       vc->vc_saved_x          = vc->vc_x;
-       vc->vc_saved_y          = vc->vc_y;
-       vc->vc_s_intensity      = vc->vc_intensity;
-       vc->vc_s_italic         = vc->vc_italic;
-       vc->vc_s_underline      = vc->vc_underline;
-       vc->vc_s_blink          = vc->vc_blink;
-       vc->vc_s_reverse        = vc->vc_reverse;
-       vc->vc_s_charset        = vc->vc_charset;
-       vc->vc_s_color          = vc->vc_color;
-       vc->vc_saved_G0         = vc->vc_G0_charset;
-       vc->vc_saved_G1         = vc->vc_G1_charset;
-}
-
-/* console_sem is held */
-static void restore_cur(struct vc_data *vc)
-{
-       gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y);
-       vc->vc_intensity        = vc->vc_s_intensity;
-       vc->vc_italic           = vc->vc_s_italic;
-       vc->vc_underline        = vc->vc_s_underline;
-       vc->vc_blink            = vc->vc_s_blink;
-       vc->vc_reverse          = vc->vc_s_reverse;
-       vc->vc_charset          = vc->vc_s_charset;
-       vc->vc_color            = vc->vc_s_color;
-       vc->vc_G0_charset       = vc->vc_saved_G0;
-       vc->vc_G1_charset       = vc->vc_saved_G1;
-       vc->vc_translate        = set_translate(vc->vc_charset ? vc->vc_G1_charset : vc->vc_G0_charset, vc);
-       update_attr(vc);
-       vc->vc_need_wrap = 0;
-}
-
-enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
-       EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
-       ESpalette };
-
-/* console_sem is held (except via vc_init()) */
-static void reset_terminal(struct vc_data *vc, int do_clear)
-{
-       vc->vc_top              = 0;
-       vc->vc_bottom           = vc->vc_rows;
-       vc->vc_state            = ESnormal;
-       vc->vc_ques             = 0;
-       vc->vc_translate        = set_translate(LAT1_MAP, vc);
-       vc->vc_G0_charset       = LAT1_MAP;
-       vc->vc_G1_charset       = GRAF_MAP;
-       vc->vc_charset          = 0;
-       vc->vc_need_wrap        = 0;
-       vc->vc_report_mouse     = 0;
-       vc->vc_utf              = default_utf8;
-       vc->vc_utf_count        = 0;
-
-       vc->vc_disp_ctrl        = 0;
-       vc->vc_toggle_meta      = 0;
-
-       vc->vc_decscnm          = 0;
-       vc->vc_decom            = 0;
-       vc->vc_decawm           = 1;
-       vc->vc_deccm            = global_cursor_default;
-       vc->vc_decim            = 0;
-
-       set_kbd(vc, decarm);
-       clr_kbd(vc, decckm);
-       clr_kbd(vc, kbdapplic);
-       clr_kbd(vc, lnm);
-       kbd_table[vc->vc_num].lockstate = 0;
-       kbd_table[vc->vc_num].slockstate = 0;
-       kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS;
-       kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate;
-       /* do not do set_leds here because this causes an endless tasklet loop
-          when the keyboard hasn't been initialized yet */
-
-       vc->vc_cursor_type = cur_default;
-       vc->vc_complement_mask = vc->vc_s_complement_mask;
-
-       default_attr(vc);
-       update_attr(vc);
-
-       vc->vc_tab_stop[0]      = 0x01010100;
-       vc->vc_tab_stop[1]      =
-       vc->vc_tab_stop[2]      =
-       vc->vc_tab_stop[3]      =
-       vc->vc_tab_stop[4]      =
-       vc->vc_tab_stop[5]      =
-       vc->vc_tab_stop[6]      =
-       vc->vc_tab_stop[7]      = 0x01010101;
-
-       vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
-       vc->vc_bell_duration = DEFAULT_BELL_DURATION;
-
-       gotoxy(vc, 0, 0);
-       save_cur(vc);
-       if (do_clear)
-           csi_J(vc, 2);
-}
-
-/* console_sem is held */
-static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
-{
-       /*
-        *  Control characters can be used in the _middle_
-        *  of an escape sequence.
-        */
-       switch (c) {
-       case 0:
-               return;
-       case 7:
-               if (vc->vc_bell_duration)
-                       kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
-               return;
-       case 8:
-               bs(vc);
-               return;
-       case 9:
-               vc->vc_pos -= (vc->vc_x << 1);
-               while (vc->vc_x < vc->vc_cols - 1) {
-                       vc->vc_x++;
-                       if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31)))
-                               break;
-               }
-               vc->vc_pos += (vc->vc_x << 1);
-               notify_write(vc, '\t');
-               return;
-       case 10: case 11: case 12:
-               lf(vc);
-               if (!is_kbd(vc, lnm))
-                       return;
-       case 13:
-               cr(vc);
-               return;
-       case 14:
-               vc->vc_charset = 1;
-               vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
-               vc->vc_disp_ctrl = 1;
-               return;
-       case 15:
-               vc->vc_charset = 0;
-               vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
-               vc->vc_disp_ctrl = 0;
-               return;
-       case 24: case 26:
-               vc->vc_state = ESnormal;
-               return;
-       case 27:
-               vc->vc_state = ESesc;
-               return;
-       case 127:
-               del(vc);
-               return;
-       case 128+27:
-               vc->vc_state = ESsquare;
-               return;
-       }
-       switch(vc->vc_state) {
-       case ESesc:
-               vc->vc_state = ESnormal;
-               switch (c) {
-               case '[':
-                       vc->vc_state = ESsquare;
-                       return;
-               case ']':
-                       vc->vc_state = ESnonstd;
-                       return;
-               case '%':
-                       vc->vc_state = ESpercent;
-                       return;
-               case 'E':
-                       cr(vc);
-                       lf(vc);
-                       return;
-               case 'M':
-                       ri(vc);
-                       return;
-               case 'D':
-                       lf(vc);
-                       return;
-               case 'H':
-                       vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31));
-                       return;
-               case 'Z':
-                       respond_ID(tty);
-                       return;
-               case '7':
-                       save_cur(vc);
-                       return;
-               case '8':
-                       restore_cur(vc);
-                       return;
-               case '(':
-                       vc->vc_state = ESsetG0;
-                       return;
-               case ')':
-                       vc->vc_state = ESsetG1;
-                       return;
-               case '#':
-                       vc->vc_state = EShash;
-                       return;
-               case 'c':
-                       reset_terminal(vc, 1);
-                       return;
-               case '>':  /* Numeric keypad */
-                       clr_kbd(vc, kbdapplic);
-                       return;
-               case '=':  /* Appl. keypad */
-                       set_kbd(vc, kbdapplic);
-                       return;
-               }
-               return;
-       case ESnonstd:
-               if (c=='P') {   /* palette escape sequence */
-                       for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
-                               vc->vc_par[vc->vc_npar] = 0;
-                       vc->vc_npar = 0;
-                       vc->vc_state = ESpalette;
-                       return;
-               } else if (c=='R') {   /* reset palette */
-                       reset_palette(vc);
-                       vc->vc_state = ESnormal;
-               } else
-                       vc->vc_state = ESnormal;
-               return;
-       case ESpalette:
-               if (isxdigit(c)) {
-                       vc->vc_par[vc->vc_npar++] = hex_to_bin(c);
-                       if (vc->vc_npar == 7) {
-                               int i = vc->vc_par[0] * 3, j = 1;
-                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
-                               vc->vc_palette[i++] += vc->vc_par[j++];
-                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
-                               vc->vc_palette[i++] += vc->vc_par[j++];
-                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
-                               vc->vc_palette[i] += vc->vc_par[j];
-                               set_palette(vc);
-                               vc->vc_state = ESnormal;
-                       }
-               } else
-                       vc->vc_state = ESnormal;
-               return;
-       case ESsquare:
-               for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
-                       vc->vc_par[vc->vc_npar] = 0;
-               vc->vc_npar = 0;
-               vc->vc_state = ESgetpars;
-               if (c == '[') { /* Function key */
-                       vc->vc_state=ESfunckey;
-                       return;
-               }
-               vc->vc_ques = (c == '?');
-               if (vc->vc_ques)
-                       return;
-       case ESgetpars:
-               if (c == ';' && vc->vc_npar < NPAR - 1) {
-                       vc->vc_npar++;
-                       return;
-               } else if (c>='0' && c<='9') {
-                       vc->vc_par[vc->vc_npar] *= 10;
-                       vc->vc_par[vc->vc_npar] += c - '0';
-                       return;
-               } else
-                       vc->vc_state = ESgotpars;
-       case ESgotpars:
-               vc->vc_state = ESnormal;
-               switch(c) {
-               case 'h':
-                       set_mode(vc, 1);
-                       return;
-               case 'l':
-                       set_mode(vc, 0);
-                       return;
-               case 'c':
-                       if (vc->vc_ques) {
-                               if (vc->vc_par[0])
-                                       vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16);
-                               else
-                                       vc->vc_cursor_type = cur_default;
-                               return;
-                       }
-                       break;
-               case 'm':
-                       if (vc->vc_ques) {
-                               clear_selection();
-                               if (vc->vc_par[0])
-                                       vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1];
-                               else
-                                       vc->vc_complement_mask = vc->vc_s_complement_mask;
-                               return;
-                       }
-                       break;
-               case 'n':
-                       if (!vc->vc_ques) {
-                               if (vc->vc_par[0] == 5)
-                                       status_report(tty);
-                               else if (vc->vc_par[0] == 6)
-                                       cursor_report(vc, tty);
-                       }
-                       return;
-               }
-               if (vc->vc_ques) {
-                       vc->vc_ques = 0;
-                       return;
-               }
-               switch(c) {
-               case 'G': case '`':
-                       if (vc->vc_par[0])
-                               vc->vc_par[0]--;
-                       gotoxy(vc, vc->vc_par[0], vc->vc_y);
-                       return;
-               case 'A':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, vc->vc_x, vc->vc_y - vc->vc_par[0]);
-                       return;
-               case 'B': case 'e':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, vc->vc_x, vc->vc_y + vc->vc_par[0]);
-                       return;
-               case 'C': case 'a':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, vc->vc_x + vc->vc_par[0], vc->vc_y);
-                       return;
-               case 'D':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, vc->vc_x - vc->vc_par[0], vc->vc_y);
-                       return;
-               case 'E':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, 0, vc->vc_y + vc->vc_par[0]);
-                       return;
-               case 'F':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, 0, vc->vc_y - vc->vc_par[0]);
-                       return;
-               case 'd':
-                       if (vc->vc_par[0])
-                               vc->vc_par[0]--;
-                       gotoxay(vc, vc->vc_x ,vc->vc_par[0]);
-                       return;
-               case 'H': case 'f':
-                       if (vc->vc_par[0])
-                               vc->vc_par[0]--;
-                       if (vc->vc_par[1])
-                               vc->vc_par[1]--;
-                       gotoxay(vc, vc->vc_par[1], vc->vc_par[0]);
-                       return;
-               case 'J':
-                       csi_J(vc, vc->vc_par[0]);
-                       return;
-               case 'K':
-                       csi_K(vc, vc->vc_par[0]);
-                       return;
-               case 'L':
-                       csi_L(vc, vc->vc_par[0]);
-                       return;
-               case 'M':
-                       csi_M(vc, vc->vc_par[0]);
-                       return;
-               case 'P':
-                       csi_P(vc, vc->vc_par[0]);
-                       return;
-               case 'c':
-                       if (!vc->vc_par[0])
-                               respond_ID(tty);
-                       return;
-               case 'g':
-                       if (!vc->vc_par[0])
-                               vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31));
-                       else if (vc->vc_par[0] == 3) {
-                               vc->vc_tab_stop[0] =
-                                       vc->vc_tab_stop[1] =
-                                       vc->vc_tab_stop[2] =
-                                       vc->vc_tab_stop[3] =
-                                       vc->vc_tab_stop[4] =
-                                       vc->vc_tab_stop[5] =
-                                       vc->vc_tab_stop[6] =
-                                       vc->vc_tab_stop[7] = 0;
-                       }
-                       return;
-               case 'm':
-                       csi_m(vc);
-                       return;
-               case 'q': /* DECLL - but only 3 leds */
-                       /* map 0,1,2,3 to 0,1,2,4 */
-                       if (vc->vc_par[0] < 4)
-                               setledstate(kbd_table + vc->vc_num,
-                                           (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
-                       return;
-               case 'r':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       if (!vc->vc_par[1])
-                               vc->vc_par[1] = vc->vc_rows;
-                       /* Minimum allowed region is 2 lines */
-                       if (vc->vc_par[0] < vc->vc_par[1] &&
-                           vc->vc_par[1] <= vc->vc_rows) {
-                               vc->vc_top = vc->vc_par[0] - 1;
-                               vc->vc_bottom = vc->vc_par[1];
-                               gotoxay(vc, 0, 0);
-                       }
-                       return;
-               case 's':
-                       save_cur(vc);
-                       return;
-               case 'u':
-                       restore_cur(vc);
-                       return;
-               case 'X':
-                       csi_X(vc, vc->vc_par[0]);
-                       return;
-               case '@':
-                       csi_at(vc, vc->vc_par[0]);
-                       return;
-               case ']': /* setterm functions */
-                       setterm_command(vc);
-                       return;
-               }
-               return;
-       case ESpercent:
-               vc->vc_state = ESnormal;
-               switch (c) {
-               case '@':  /* defined in ISO 2022 */
-                       vc->vc_utf = 0;
-                       return;
-               case 'G':  /* prelim official escape code */
-               case '8':  /* retained for compatibility */
-                       vc->vc_utf = 1;
-                       return;
-               }
-               return;
-       case ESfunckey:
-               vc->vc_state = ESnormal;
-               return;
-       case EShash:
-               vc->vc_state = ESnormal;
-               if (c == '8') {
-                       /* DEC screen alignment test. kludge :-) */
-                       vc->vc_video_erase_char =
-                               (vc->vc_video_erase_char & 0xff00) | 'E';
-                       csi_J(vc, 2);
-                       vc->vc_video_erase_char =
-                               (vc->vc_video_erase_char & 0xff00) | ' ';
-                       do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
-               }
-               return;
-       case ESsetG0:
-               if (c == '0')
-                       vc->vc_G0_charset = GRAF_MAP;
-               else if (c == 'B')
-                       vc->vc_G0_charset = LAT1_MAP;
-               else if (c == 'U')
-                       vc->vc_G0_charset = IBMPC_MAP;
-               else if (c == 'K')
-                       vc->vc_G0_charset = USER_MAP;
-               if (vc->vc_charset == 0)
-                       vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
-               vc->vc_state = ESnormal;
-               return;
-       case ESsetG1:
-               if (c == '0')
-                       vc->vc_G1_charset = GRAF_MAP;
-               else if (c == 'B')
-                       vc->vc_G1_charset = LAT1_MAP;
-               else if (c == 'U')
-                       vc->vc_G1_charset = IBMPC_MAP;
-               else if (c == 'K')
-                       vc->vc_G1_charset = USER_MAP;
-               if (vc->vc_charset == 1)
-                       vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
-               vc->vc_state = ESnormal;
-               return;
-       default:
-               vc->vc_state = ESnormal;
-       }
-}
-
-/* This is a temporary buffer used to prepare a tty console write
- * so that we can easily avoid touching user space while holding the
- * console spinlock.  It is allocated in con_init and is shared by
- * this code and the vc_screen read/write tty calls.
- *
- * We have to allocate this statically in the kernel data section
- * since console_init (and thus con_init) are called before any
- * kernel memory allocation is available.
- */
-char con_buf[CON_BUF_SIZE];
-DEFINE_MUTEX(con_buf_mtx);
-
-/* is_double_width() is based on the wcwidth() implementation by
- * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
- * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
- */
-struct interval {
-       uint32_t first;
-       uint32_t last;
-};
-
-static int bisearch(uint32_t ucs, const struct interval *table, int max)
-{
-       int min = 0;
-       int mid;
-
-       if (ucs < table[0].first || ucs > table[max].last)
-               return 0;
-       while (max >= min) {
-               mid = (min + max) / 2;
-               if (ucs > table[mid].last)
-                       min = mid + 1;
-               else if (ucs < table[mid].first)
-                       max = mid - 1;
-               else
-                       return 1;
-       }
-       return 0;
-}
-
-static int is_double_width(uint32_t ucs)
-{
-       static const struct interval double_width[] = {
-               { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E },
-               { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF },
-               { 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 },
-               { 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD }
-       };
-       return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1);
-}
-
-/* acquires console_sem */
-static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
-#ifdef VT_BUF_VRAM_ONLY
-#define FLUSH do { } while(0);
-#else
-#define FLUSH if (draw_x >= 0) { \
-       vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \
-       draw_x = -1; \
-       }
-#endif
-
-       int c, tc, ok, n = 0, draw_x = -1;
-       unsigned int currcons;
-       unsigned long draw_from = 0, draw_to = 0;
-       struct vc_data *vc;
-       unsigned char vc_attr;
-       struct vt_notifier_param param;
-       uint8_t rescan;
-       uint8_t inverse;
-       uint8_t width;
-       u16 himask, charmask;
-
-       if (in_interrupt())
-               return count;
-
-       might_sleep();
-
-       acquire_console_sem();
-       vc = tty->driver_data;
-       if (vc == NULL) {
-               printk(KERN_ERR "vt: argh, driver_data is NULL !\n");
-               release_console_sem();
-               return 0;
-       }
-
-       currcons = vc->vc_num;
-       if (!vc_cons_allocated(currcons)) {
-           /* could this happen? */
-               printk_once("con_write: tty %d not allocated\n", currcons+1);
-           release_console_sem();
-           return 0;
-       }
-
-       himask = vc->vc_hi_font_mask;
-       charmask = himask ? 0x1ff : 0xff;
-
-       /* undraw cursor first */
-       if (IS_FG(vc))
-               hide_cursor(vc);
-
-       param.vc = vc;
-
-       while (!tty->stopped && count) {
-               int orig = *buf;
-               c = orig;
-               buf++;
-               n++;
-               count--;
-               rescan = 0;
-               inverse = 0;
-               width = 1;
-
-               /* Do no translation at all in control states */
-               if (vc->vc_state != ESnormal) {
-                       tc = c;
-               } else if (vc->vc_utf && !vc->vc_disp_ctrl) {
-                   /* Combine UTF-8 into Unicode in vc_utf_char.
-                    * vc_utf_count is the number of continuation bytes still
-                    * expected to arrive.
-                    * vc_npar is the number of continuation bytes arrived so
-                    * far
-                    */
-rescan_last_byte:
-                   if ((c & 0xc0) == 0x80) {
-                       /* Continuation byte received */
-                       static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff };
-                       if (vc->vc_utf_count) {
-                           vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
-                           vc->vc_npar++;
-                           if (--vc->vc_utf_count) {
-                               /* Still need some bytes */
-                               continue;
-                           }
-                           /* Got a whole character */
-                           c = vc->vc_utf_char;
-                           /* Reject overlong sequences */
-                           if (c <= utf8_length_changes[vc->vc_npar - 1] ||
-                                       c > utf8_length_changes[vc->vc_npar])
-                               c = 0xfffd;
-                       } else {
-                           /* Unexpected continuation byte */
-                           vc->vc_utf_count = 0;
-                           c = 0xfffd;
-                       }
-                   } else {
-                       /* Single ASCII byte or first byte of a sequence received */
-                       if (vc->vc_utf_count) {
-                           /* Continuation byte expected */
-                           rescan = 1;
-                           vc->vc_utf_count = 0;
-                           c = 0xfffd;
-                       } else if (c > 0x7f) {
-                           /* First byte of a multibyte sequence received */
-                           vc->vc_npar = 0;
-                           if ((c & 0xe0) == 0xc0) {
-                               vc->vc_utf_count = 1;
-                               vc->vc_utf_char = (c & 0x1f);
-                           } else if ((c & 0xf0) == 0xe0) {
-                               vc->vc_utf_count = 2;
-                               vc->vc_utf_char = (c & 0x0f);
-                           } else if ((c & 0xf8) == 0xf0) {
-                               vc->vc_utf_count = 3;
-                               vc->vc_utf_char = (c & 0x07);
-                           } else if ((c & 0xfc) == 0xf8) {
-                               vc->vc_utf_count = 4;
-                               vc->vc_utf_char = (c & 0x03);
-                           } else if ((c & 0xfe) == 0xfc) {
-                               vc->vc_utf_count = 5;
-                               vc->vc_utf_char = (c & 0x01);
-                           } else {
-                               /* 254 and 255 are invalid */
-                               c = 0xfffd;
-                           }
-                           if (vc->vc_utf_count) {
-                               /* Still need some bytes */
-                               continue;
-                           }
-                       }
-                       /* Nothing to do if an ASCII byte was received */
-                   }
-                   /* End of UTF-8 decoding. */
-                   /* c is the received character, or U+FFFD for invalid sequences. */
-                   /* Replace invalid Unicode code points with U+FFFD too */
-                   if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
-                       c = 0xfffd;
-                   tc = c;
-               } else {        /* no utf or alternate charset mode */
-                   tc = vc_translate(vc, c);
-               }
-
-               param.c = tc;
-               if (atomic_notifier_call_chain(&vt_notifier_list, VT_PREWRITE,
-                                       &param) == NOTIFY_STOP)
-                       continue;
-
-                /* If the original code was a control character we
-                 * only allow a glyph to be displayed if the code is
-                 * not normally used (such as for cursor movement) or
-                 * if the disp_ctrl mode has been explicitly enabled.
-                 * Certain characters (as given by the CTRL_ALWAYS
-                 * bitmap) are always displayed as control characters,
-                 * as the console would be pretty useless without
-                 * them; to display an arbitrary font position use the
-                 * direct-to-font zone in UTF-8 mode.
-                 */
-                ok = tc && (c >= 32 ||
-                           !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
-                                 vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
-                       && (c != 127 || vc->vc_disp_ctrl)
-                       && (c != 128+27);
-
-               if (vc->vc_state == ESnormal && ok) {
-                       if (vc->vc_utf && !vc->vc_disp_ctrl) {
-                               if (is_double_width(c))
-                                       width = 2;
-                       }
-                       /* Now try to find out how to display it */
-                       tc = conv_uni_to_pc(vc, tc);
-                       if (tc & ~charmask) {
-                               if (tc == -1 || tc == -2) {
-                                   continue; /* nothing to display */
-                               }
-                               /* Glyph not found */
-                               if ((!(vc->vc_utf && !vc->vc_disp_ctrl) || c < 128) && !(c & ~charmask)) {
-                                   /* In legacy mode use the glyph we get by a 1:1 mapping.
-                                      This would make absolutely no sense with Unicode in mind,
-                                      but do this for ASCII characters since a font may lack
-                                      Unicode mapping info and we don't want to end up with
-                                      having question marks only. */
-                                   tc = c;
-                               } else {
-                                   /* Display U+FFFD. If it's not found, display an inverse question mark. */
-                                   tc = conv_uni_to_pc(vc, 0xfffd);
-                                   if (tc < 0) {
-                                       inverse = 1;
-                                       tc = conv_uni_to_pc(vc, '?');
-                                       if (tc < 0) tc = '?';
-                                   }
-                               }
-                       }
-
-                       if (!inverse) {
-                               vc_attr = vc->vc_attr;
-                       } else {
-                               /* invert vc_attr */
-                               if (!vc->vc_can_do_color) {
-                                       vc_attr = (vc->vc_attr) ^ 0x08;
-                               } else if (vc->vc_hi_font_mask == 0x100) {
-                                       vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4);
-                               } else {
-                                       vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
-                               }
-                               FLUSH
-                       }
-
-                       while (1) {
-                               if (vc->vc_need_wrap || vc->vc_decim)
-                                       FLUSH
-                               if (vc->vc_need_wrap) {
-                                       cr(vc);
-                                       lf(vc);
-                               }
-                               if (vc->vc_decim)
-                                       insert_char(vc, 1);
-                               scr_writew(himask ?
-                                            ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
-                                            (vc_attr << 8) + tc,
-                                          (u16 *) vc->vc_pos);
-                               if (DO_UPDATE(vc) && draw_x < 0) {
-                                       draw_x = vc->vc_x;
-                                       draw_from = vc->vc_pos;
-                               }
-                               if (vc->vc_x == vc->vc_cols - 1) {
-                                       vc->vc_need_wrap = vc->vc_decawm;
-                                       draw_to = vc->vc_pos + 2;
-                               } else {
-                                       vc->vc_x++;
-                                       draw_to = (vc->vc_pos += 2);
-                               }
-
-                               if (!--width) break;
-
-                               tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
-                               if (tc < 0) tc = ' ';
-                       }
-                       notify_write(vc, c);
-
-                       if (inverse) {
-                               FLUSH
-                       }
-
-                       if (rescan) {
-                               rescan = 0;
-                               inverse = 0;
-                               width = 1;
-                               c = orig;
-                               goto rescan_last_byte;
-                       }
-                       continue;
-               }
-               FLUSH
-               do_con_trol(tty, vc, orig);
-       }
-       FLUSH
-       console_conditional_schedule();
-       release_console_sem();
-       notify_update(vc);
-       return n;
-#undef FLUSH
-}
-
-/*
- * This is the console switching callback.
- *
- * Doing console switching in a process context allows
- * us to do the switches asynchronously (needed when we want
- * to switch due to a keyboard interrupt).  Synchronization
- * with other console code and prevention of re-entrancy is
- * ensured with console_sem.
- */
-static void console_callback(struct work_struct *ignored)
-{
-       acquire_console_sem();
-
-       if (want_console >= 0) {
-               if (want_console != fg_console &&
-                   vc_cons_allocated(want_console)) {
-                       hide_cursor(vc_cons[fg_console].d);
-                       change_console(vc_cons[want_console].d);
-                       /* we only changed when the console had already
-                          been allocated - a new console is not created
-                          in an interrupt routine */
-               }
-               want_console = -1;
-       }
-       if (do_poke_blanked_console) { /* do not unblank for a LED change */
-               do_poke_blanked_console = 0;
-               poke_blanked_console();
-       }
-       if (scrollback_delta) {
-               struct vc_data *vc = vc_cons[fg_console].d;
-               clear_selection();
-               if (vc->vc_mode == KD_TEXT)
-                       vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
-               scrollback_delta = 0;
-       }
-       if (blank_timer_expired) {
-               do_blank_screen(0);
-               blank_timer_expired = 0;
-       }
-       notify_update(vc_cons[fg_console].d);
-
-       release_console_sem();
-}
-
-int set_console(int nr)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-
-       if (!vc_cons_allocated(nr) || vt_dont_switch ||
-               (vc->vt_mode.mode == VT_AUTO && vc->vc_mode == KD_GRAPHICS)) {
-
-               /*
-                * Console switch will fail in console_callback() or
-                * change_console() so there is no point scheduling
-                * the callback
-                *
-                * Existing set_console() users don't check the return
-                * value so this shouldn't break anything
-                */
-               return -EINVAL;
-       }
-
-       want_console = nr;
-       schedule_console_callback();
-
-       return 0;
-}
-
-struct tty_driver *console_driver;
-
-#ifdef CONFIG_VT_CONSOLE
-
-/**
- * vt_kmsg_redirect() - Sets/gets the kernel message console
- * @new:       The new virtual terminal number or -1 if the console should stay
- *             unchanged
- *
- * By default, the kernel messages are always printed on the current virtual
- * console. However, the user may modify that default with the
- * TIOCL_SETKMSGREDIRECT ioctl call.
- *
- * This function sets the kernel message console to be @new. It returns the old
- * virtual console number. The virtual terminal number 0 (both as parameter and
- * return value) means no redirection (i.e. always printed on the currently
- * active console).
- *
- * The parameter -1 means that only the current console is returned, but the
- * value is not modified. You may use the macro vt_get_kmsg_redirect() in that
- * case to make the code more understandable.
- *
- * When the kernel is compiled without CONFIG_VT_CONSOLE, this function ignores
- * the parameter and always returns 0.
- */
-int vt_kmsg_redirect(int new)
-{
-       static int kmsg_con;
-
-       if (new != -1)
-               return xchg(&kmsg_con, new);
-       else
-               return kmsg_con;
-}
-
-/*
- *     Console on virtual terminal
- *
- * The console must be locked when we get here.
- */
-
-static void vt_console_print(struct console *co, const char *b, unsigned count)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-       unsigned char c;
-       static DEFINE_SPINLOCK(printing_lock);
-       const ushort *start;
-       ushort cnt = 0;
-       ushort myx;
-       int kmsg_console;
-
-       /* console busy or not yet initialized */
-       if (!printable)
-               return;
-       if (!spin_trylock(&printing_lock))
-               return;
-
-       kmsg_console = vt_get_kmsg_redirect();
-       if (kmsg_console && vc_cons_allocated(kmsg_console - 1))
-               vc = vc_cons[kmsg_console - 1].d;
-
-       /* read `x' only after setting currcons properly (otherwise
-          the `x' macro will read the x of the foreground console). */
-       myx = vc->vc_x;
-
-       if (!vc_cons_allocated(fg_console)) {
-               /* impossible */
-               /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
-               goto quit;
-       }
-
-       if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc))
-               goto quit;
-
-       /* undraw cursor first */
-       if (IS_FG(vc))
-               hide_cursor(vc);
-
-       start = (ushort *)vc->vc_pos;
-
-       /* Contrived structure to try to emulate original need_wrap behaviour
-        * Problems caused when we have need_wrap set on '\n' character */
-       while (count--) {
-               c = *b++;
-               if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
-                       if (cnt > 0) {
-                               if (CON_IS_VISIBLE(vc))
-                                       vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
-                               vc->vc_x += cnt;
-                               if (vc->vc_need_wrap)
-                                       vc->vc_x--;
-                               cnt = 0;
-                       }
-                       if (c == 8) {           /* backspace */
-                               bs(vc);
-                               start = (ushort *)vc->vc_pos;
-                               myx = vc->vc_x;
-                               continue;
-                       }
-                       if (c != 13)
-                               lf(vc);
-                       cr(vc);
-                       start = (ushort *)vc->vc_pos;
-                       myx = vc->vc_x;
-                       if (c == 10 || c == 13)
-                               continue;
-               }
-               scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
-               notify_write(vc, c);
-               cnt++;
-               if (myx == vc->vc_cols - 1) {
-                       vc->vc_need_wrap = 1;
-                       continue;
-               }
-               vc->vc_pos += 2;
-               myx++;
-       }
-       if (cnt > 0) {
-               if (CON_IS_VISIBLE(vc))
-                       vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
-               vc->vc_x += cnt;
-               if (vc->vc_x == vc->vc_cols) {
-                       vc->vc_x--;
-                       vc->vc_need_wrap = 1;
-               }
-       }
-       set_cursor(vc);
-       notify_update(vc);
-
-quit:
-       spin_unlock(&printing_lock);
-}
-
-static struct tty_driver *vt_console_device(struct console *c, int *index)
-{
-       *index = c->index ? c->index-1 : fg_console;
-       return console_driver;
-}
-
-static struct console vt_console_driver = {
-       .name           = "tty",
-       .write          = vt_console_print,
-       .device         = vt_console_device,
-       .unblank        = unblank_screen,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-};
-#endif
-
-/*
- *     Handling of Linux-specific VC ioctls
- */
-
-/*
- * Generally a bit racy with respect to console_sem().
- *
- * There are some functions which don't need it.
- *
- * There are some functions which can sleep for arbitrary periods
- * (paste_selection) but we don't need the lock there anyway.
- *
- * set_selection has locking, and definitely needs it
- */
-
-int tioclinux(struct tty_struct *tty, unsigned long arg)
-{
-       char type, data;
-       char __user *p = (char __user *)arg;
-       int lines;
-       int ret;
-
-       if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       if (get_user(type, p))
-               return -EFAULT;
-       ret = 0;
-
-       switch (type)
-       {
-               case TIOCL_SETSEL:
-                       acquire_console_sem();
-                       ret = set_selection((struct tiocl_selection __user *)(p+1), tty);
-                       release_console_sem();
-                       break;
-               case TIOCL_PASTESEL:
-                       ret = paste_selection(tty);
-                       break;
-               case TIOCL_UNBLANKSCREEN:
-                       acquire_console_sem();
-                       unblank_screen();
-                       release_console_sem();
-                       break;
-               case TIOCL_SELLOADLUT:
-                       ret = sel_loadlut(p);
-                       break;
-               case TIOCL_GETSHIFTSTATE:
-
-       /*
-        * Make it possible to react to Shift+Mousebutton.
-        * Note that 'shift_state' is an undocumented
-        * kernel-internal variable; programs not closely
-        * related to the kernel should not use this.
-        */
-                       data = shift_state;
-                       ret = __put_user(data, p);
-                       break;
-               case TIOCL_GETMOUSEREPORTING:
-                       data = mouse_reporting();
-                       ret = __put_user(data, p);
-                       break;
-               case TIOCL_SETVESABLANK:
-                       ret = set_vesa_blanking(p);
-                       break;
-               case TIOCL_GETKMSGREDIRECT:
-                       data = vt_get_kmsg_redirect();
-                       ret = __put_user(data, p);
-                       break;
-               case TIOCL_SETKMSGREDIRECT:
-                       if (!capable(CAP_SYS_ADMIN)) {
-                               ret = -EPERM;
-                       } else {
-                               if (get_user(data, p+1))
-                                       ret = -EFAULT;
-                               else
-                                       vt_kmsg_redirect(data);
-                       }
-                       break;
-               case TIOCL_GETFGCONSOLE:
-                       ret = fg_console;
-                       break;
-               case TIOCL_SCROLLCONSOLE:
-                       if (get_user(lines, (s32 __user *)(p+4))) {
-                               ret = -EFAULT;
-                       } else {
-                               scrollfront(vc_cons[fg_console].d, lines);
-                               ret = 0;
-                       }
-                       break;
-               case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
-                       acquire_console_sem();
-                       ignore_poke = 1;
-                       do_blank_screen(0);
-                       release_console_sem();
-                       break;
-               case TIOCL_BLANKEDSCREEN:
-                       ret = console_blanked;
-                       break;
-               default:
-                       ret = -EINVAL;
-                       break;
-       }
-       return ret;
-}
-
-/*
- * /dev/ttyN handling
- */
-
-static int con_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
-       int     retval;
-
-       retval = do_con_write(tty, buf, count);
-       con_flush_chars(tty);
-
-       return retval;
-}
-
-static int con_put_char(struct tty_struct *tty, unsigned char ch)
-{
-       if (in_interrupt())
-               return 0;       /* n_r3964 calls put_char() from interrupt context */
-       return do_con_write(tty, &ch, 1);
-}
-
-static int con_write_room(struct tty_struct *tty)
-{
-       if (tty->stopped)
-               return 0;
-       return 32768;           /* No limit, really; we're not buffering */
-}
-
-static int con_chars_in_buffer(struct tty_struct *tty)
-{
-       return 0;               /* we're not buffering */
-}
-
-/*
- * con_throttle and con_unthrottle are only used for
- * paste_selection(), which has to stuff in a large number of
- * characters...
- */
-static void con_throttle(struct tty_struct *tty)
-{
-}
-
-static void con_unthrottle(struct tty_struct *tty)
-{
-       struct vc_data *vc = tty->driver_data;
-
-       wake_up_interruptible(&vc->paste_wait);
-}
-
-/*
- * Turn the Scroll-Lock LED on when the tty is stopped
- */
-static void con_stop(struct tty_struct *tty)
-{
-       int console_num;
-       if (!tty)
-               return;
-       console_num = tty->index;
-       if (!vc_cons_allocated(console_num))
-               return;
-       set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
-       set_leds();
-}
-
-/*
- * Turn the Scroll-Lock LED off when the console is started
- */
-static void con_start(struct tty_struct *tty)
-{
-       int console_num;
-       if (!tty)
-               return;
-       console_num = tty->index;
-       if (!vc_cons_allocated(console_num))
-               return;
-       clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
-       set_leds();
-}
-
-static void con_flush_chars(struct tty_struct *tty)
-{
-       struct vc_data *vc;
-
-       if (in_interrupt())     /* from flush_to_ldisc */
-               return;
-
-       /* if we race with con_close(), vt may be null */
-       acquire_console_sem();
-       vc = tty->driver_data;
-       if (vc)
-               set_cursor(vc);
-       release_console_sem();
-}
-
-/*
- * Allocate the console screen memory.
- */
-static int con_open(struct tty_struct *tty, struct file *filp)
-{
-       unsigned int currcons = tty->index;
-       int ret = 0;
-
-       acquire_console_sem();
-       if (tty->driver_data == NULL) {
-               ret = vc_allocate(currcons);
-               if (ret == 0) {
-                       struct vc_data *vc = vc_cons[currcons].d;
-
-                       /* Still being freed */
-                       if (vc->port.tty) {
-                               release_console_sem();
-                               return -ERESTARTSYS;
-                       }
-                       tty->driver_data = vc;
-                       vc->port.tty = tty;
-
-                       if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
-                               tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
-                               tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
-                       }
-                       if (vc->vc_utf)
-                               tty->termios->c_iflag |= IUTF8;
-                       else
-                               tty->termios->c_iflag &= ~IUTF8;
-                       release_console_sem();
-                       return ret;
-               }
-       }
-       release_console_sem();
-       return ret;
-}
-
-static void con_close(struct tty_struct *tty, struct file *filp)
-{
-       /* Nothing to do - we defer to shutdown */
-}
-
-static void con_shutdown(struct tty_struct *tty)
-{
-       struct vc_data *vc = tty->driver_data;
-       BUG_ON(vc == NULL);
-       acquire_console_sem();
-       vc->port.tty = NULL;
-       release_console_sem();
-       tty_shutdown(tty);
-}
-
-static int default_italic_color    = 2; // green (ASCII)
-static int default_underline_color = 3; // cyan (ASCII)
-module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
-module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
-
-static void vc_init(struct vc_data *vc, unsigned int rows,
-                   unsigned int cols, int do_clear)
-{
-       int j, k ;
-
-       vc->vc_cols = cols;
-       vc->vc_rows = rows;
-       vc->vc_size_row = cols << 1;
-       vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
-
-       set_origin(vc);
-       vc->vc_pos = vc->vc_origin;
-       reset_vc(vc);
-       for (j=k=0; j<16; j++) {
-               vc->vc_palette[k++] = default_red[j] ;
-               vc->vc_palette[k++] = default_grn[j] ;
-               vc->vc_palette[k++] = default_blu[j] ;
-       }
-       vc->vc_def_color       = 0x07;   /* white */
-       vc->vc_ulcolor         = default_underline_color;
-       vc->vc_itcolor         = default_italic_color;
-       vc->vc_halfcolor       = 0x08;   /* grey */
-       init_waitqueue_head(&vc->paste_wait);
-       reset_terminal(vc, do_clear);
-}
-
-/*
- * This routine initializes console interrupts, and does nothing
- * else. If you want the screen to clear, call tty_write with
- * the appropriate escape-sequence.
- */
-
-static int __init con_init(void)
-{
-       const char *display_desc = NULL;
-       struct vc_data *vc;
-       unsigned int currcons = 0, i;
-
-       acquire_console_sem();
-
-       if (conswitchp)
-               display_desc = conswitchp->con_startup();
-       if (!display_desc) {
-               fg_console = 0;
-               release_console_sem();
-               return 0;
-       }
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               struct con_driver *con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == NULL) {
-                       con_driver->con = conswitchp;
-                       con_driver->desc = display_desc;
-                       con_driver->flag = CON_DRIVER_FLAG_INIT;
-                       con_driver->first = 0;
-                       con_driver->last = MAX_NR_CONSOLES - 1;
-                       break;
-               }
-       }
-
-       for (i = 0; i < MAX_NR_CONSOLES; i++)
-               con_driver_map[i] = conswitchp;
-
-       if (blankinterval) {
-               blank_state = blank_normal_wait;
-               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-       }
-
-       for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
-               vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
-               INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
-               tty_port_init(&vc->port);
-               visual_init(vc, currcons, 1);
-               vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
-               vc_init(vc, vc->vc_rows, vc->vc_cols,
-                       currcons || !vc->vc_sw->con_save_screen);
-       }
-       currcons = fg_console = 0;
-       master_display_fg = vc = vc_cons[currcons].d;
-       set_origin(vc);
-       save_screen(vc);
-       gotoxy(vc, vc->vc_x, vc->vc_y);
-       csi_J(vc, 0);
-       update_screen(vc);
-       printk("Console: %s %s %dx%d",
-               vc->vc_can_do_color ? "colour" : "mono",
-               display_desc, vc->vc_cols, vc->vc_rows);
-       printable = 1;
-       printk("\n");
-
-       release_console_sem();
-
-#ifdef CONFIG_VT_CONSOLE
-       register_console(&vt_console_driver);
-#endif
-       return 0;
-}
-console_initcall(con_init);
-
-static const struct tty_operations con_ops = {
-       .open = con_open,
-       .close = con_close,
-       .write = con_write,
-       .write_room = con_write_room,
-       .put_char = con_put_char,
-       .flush_chars = con_flush_chars,
-       .chars_in_buffer = con_chars_in_buffer,
-       .ioctl = vt_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl = vt_compat_ioctl,
-#endif
-       .stop = con_stop,
-       .start = con_start,
-       .throttle = con_throttle,
-       .unthrottle = con_unthrottle,
-       .resize = vt_resize,
-       .shutdown = con_shutdown
-};
-
-static struct cdev vc0_cdev;
-
-int __init vty_init(const struct file_operations *console_fops)
-{
-       cdev_init(&vc0_cdev, console_fops);
-       if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
-           register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
-               panic("Couldn't register /dev/tty0 driver\n");
-       device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
-
-       vcs_init();
-
-       console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
-       if (!console_driver)
-               panic("Couldn't allocate console driver\n");
-       console_driver->owner = THIS_MODULE;
-       console_driver->name = "tty";
-       console_driver->name_base = 1;
-       console_driver->major = TTY_MAJOR;
-       console_driver->minor_start = 1;
-       console_driver->type = TTY_DRIVER_TYPE_CONSOLE;
-       console_driver->init_termios = tty_std_termios;
-       if (default_utf8)
-               console_driver->init_termios.c_iflag |= IUTF8;
-       console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
-       tty_set_operations(console_driver, &con_ops);
-       if (tty_register_driver(console_driver))
-               panic("Couldn't register console driver\n");
-       kbd_init();
-       console_map_init();
-#ifdef CONFIG_MDA_CONSOLE
-       mda_console_init();
-#endif
-       return 0;
-}
-
-#ifndef VT_SINGLE_DRIVER
-
-static struct class *vtconsole_class;
-
-static int bind_con_driver(const struct consw *csw, int first, int last,
-                          int deflt)
-{
-       struct module *owner = csw->owner;
-       const char *desc = NULL;
-       struct con_driver *con_driver;
-       int i, j = -1, k = -1, retval = -ENODEV;
-
-       if (!try_module_get(owner))
-               return -ENODEV;
-
-       acquire_console_sem();
-
-       /* check if driver is registered */
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == csw) {
-                       desc = con_driver->desc;
-                       retval = 0;
-                       break;
-               }
-       }
-
-       if (retval)
-               goto err;
-
-       if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) {
-               csw->con_startup();
-               con_driver->flag |= CON_DRIVER_FLAG_INIT;
-       }
-
-       if (deflt) {
-               if (conswitchp)
-                       module_put(conswitchp->owner);
-
-               __module_get(owner);
-               conswitchp = csw;
-       }
-
-       first = max(first, con_driver->first);
-       last = min(last, con_driver->last);
-
-       for (i = first; i <= last; i++) {
-               int old_was_color;
-               struct vc_data *vc = vc_cons[i].d;
-
-               if (con_driver_map[i])
-                       module_put(con_driver_map[i]->owner);
-               __module_get(owner);
-               con_driver_map[i] = csw;
-
-               if (!vc || !vc->vc_sw)
-                       continue;
-
-               j = i;
-
-               if (CON_IS_VISIBLE(vc)) {
-                       k = i;
-                       save_screen(vc);
-               }
-
-               old_was_color = vc->vc_can_do_color;
-               vc->vc_sw->con_deinit(vc);
-               vc->vc_origin = (unsigned long)vc->vc_screenbuf;
-               visual_init(vc, i, 0);
-               set_origin(vc);
-               update_attr(vc);
-
-               /* If the console changed between mono <-> color, then
-                * the attributes in the screenbuf will be wrong.  The
-                * following resets all attributes to something sane.
-                */
-               if (old_was_color != vc->vc_can_do_color)
-                       clear_buffer_attributes(vc);
-       }
-
-       printk("Console: switching ");
-       if (!deflt)
-               printk("consoles %d-%d ", first+1, last+1);
-       if (j >= 0) {
-               struct vc_data *vc = vc_cons[j].d;
-
-               printk("to %s %s %dx%d\n",
-                      vc->vc_can_do_color ? "colour" : "mono",
-                      desc, vc->vc_cols, vc->vc_rows);
-
-               if (k >= 0) {
-                       vc = vc_cons[k].d;
-                       update_screen(vc);
-               }
-       } else
-               printk("to %s\n", desc);
-
-       retval = 0;
-err:
-       release_console_sem();
-       module_put(owner);
-       return retval;
-};
-
-#ifdef CONFIG_VT_HW_CONSOLE_BINDING
-static int con_is_graphics(const struct consw *csw, int first, int last)
-{
-       int i, retval = 0;
-
-       for (i = first; i <= last; i++) {
-               struct vc_data *vc = vc_cons[i].d;
-
-               if (vc && vc->vc_mode == KD_GRAPHICS) {
-                       retval = 1;
-                       break;
-               }
-       }
-
-       return retval;
-}
-
-/**
- * unbind_con_driver - unbind a console driver
- * @csw: pointer to console driver to unregister
- * @first: first in range of consoles that @csw should be unbound from
- * @last: last in range of consoles that @csw should be unbound from
- * @deflt: should next bound console driver be default after @csw is unbound?
- *
- * To unbind a driver from all possible consoles, pass 0 as @first and
- * %MAX_NR_CONSOLES as @last.
- *
- * @deflt controls whether the console that ends up replacing @csw should be
- * the default console.
- *
- * RETURNS:
- * -ENODEV if @csw isn't a registered console driver or can't be unregistered
- * or 0 on success.
- */
-int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
-{
-       struct module *owner = csw->owner;
-       const struct consw *defcsw = NULL;
-       struct con_driver *con_driver = NULL, *con_back = NULL;
-       int i, retval = -ENODEV;
-
-       if (!try_module_get(owner))
-               return -ENODEV;
-
-       acquire_console_sem();
-
-       /* check if driver is registered and if it is unbindable */
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == csw &&
-                   con_driver->flag & CON_DRIVER_FLAG_MODULE) {
-                       retval = 0;
-                       break;
-               }
-       }
-
-       if (retval) {
-               release_console_sem();
-               goto err;
-       }
-
-       retval = -ENODEV;
-
-       /* check if backup driver exists */
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_back = &registered_con_driver[i];
-
-               if (con_back->con &&
-                   !(con_back->flag & CON_DRIVER_FLAG_MODULE)) {
-                       defcsw = con_back->con;
-                       retval = 0;
-                       break;
-               }
-       }
-
-       if (retval) {
-               release_console_sem();
-               goto err;
-       }
-
-       if (!con_is_bound(csw)) {
-               release_console_sem();
-               goto err;
-       }
-
-       first = max(first, con_driver->first);
-       last = min(last, con_driver->last);
-
-       for (i = first; i <= last; i++) {
-               if (con_driver_map[i] == csw) {
-                       module_put(csw->owner);
-                       con_driver_map[i] = NULL;
-               }
-       }
-
-       if (!con_is_bound(defcsw)) {
-               const struct consw *defconsw = conswitchp;
-
-               defcsw->con_startup();
-               con_back->flag |= CON_DRIVER_FLAG_INIT;
-               /*
-                * vgacon may change the default driver to point
-                * to dummycon, we restore it here...
-                */
-               conswitchp = defconsw;
-       }
-
-       if (!con_is_bound(csw))
-               con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
-
-       release_console_sem();
-       /* ignore return value, binding should not fail */
-       bind_con_driver(defcsw, first, last, deflt);
-err:
-       module_put(owner);
-       return retval;
-
-}
-EXPORT_SYMBOL(unbind_con_driver);
-
-static int vt_bind(struct con_driver *con)
-{
-       const struct consw *defcsw = NULL, *csw = NULL;
-       int i, more = 1, first = -1, last = -1, deflt = 0;
-
-       if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
-           con_is_graphics(con->con, con->first, con->last))
-               goto err;
-
-       csw = con->con;
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               struct con_driver *con = &registered_con_driver[i];
-
-               if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) {
-                       defcsw = con->con;
-                       break;
-               }
-       }
-
-       if (!defcsw)
-               goto err;
-
-       while (more) {
-               more = 0;
-
-               for (i = con->first; i <= con->last; i++) {
-                       if (con_driver_map[i] == defcsw) {
-                               if (first == -1)
-                                       first = i;
-                               last = i;
-                               more = 1;
-                       } else if (first != -1)
-                               break;
-               }
-
-               if (first == 0 && last == MAX_NR_CONSOLES -1)
-                       deflt = 1;
-
-               if (first != -1)
-                       bind_con_driver(csw, first, last, deflt);
-
-               first = -1;
-               last = -1;
-               deflt = 0;
-       }
-
-err:
-       return 0;
-}
-
-static int vt_unbind(struct con_driver *con)
-{
-       const struct consw *csw = NULL;
-       int i, more = 1, first = -1, last = -1, deflt = 0;
-
-       if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
-           con_is_graphics(con->con, con->first, con->last))
-               goto err;
-
-       csw = con->con;
-
-       while (more) {
-               more = 0;
-
-               for (i = con->first; i <= con->last; i++) {
-                       if (con_driver_map[i] == csw) {
-                               if (first == -1)
-                                       first = i;
-                               last = i;
-                               more = 1;
-                       } else if (first != -1)
-                               break;
-               }
-
-               if (first == 0 && last == MAX_NR_CONSOLES -1)
-                       deflt = 1;
-
-               if (first != -1)
-                       unbind_con_driver(csw, first, last, deflt);
-
-               first = -1;
-               last = -1;
-               deflt = 0;
-       }
-
-err:
-       return 0;
-}
-#else
-static inline int vt_bind(struct con_driver *con)
-{
-       return 0;
-}
-static inline int vt_unbind(struct con_driver *con)
-{
-       return 0;
-}
-#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
-
-static ssize_t store_bind(struct device *dev, struct device_attribute *attr,
-                         const char *buf, size_t count)
-{
-       struct con_driver *con = dev_get_drvdata(dev);
-       int bind = simple_strtoul(buf, NULL, 0);
-
-       if (bind)
-               vt_bind(con);
-       else
-               vt_unbind(con);
-
-       return count;
-}
-
-static ssize_t show_bind(struct device *dev, struct device_attribute *attr,
-                        char *buf)
-{
-       struct con_driver *con = dev_get_drvdata(dev);
-       int bind = con_is_bound(con->con);
-
-       return snprintf(buf, PAGE_SIZE, "%i\n", bind);
-}
-
-static ssize_t show_name(struct device *dev, struct device_attribute *attr,
-                        char *buf)
-{
-       struct con_driver *con = dev_get_drvdata(dev);
-
-       return snprintf(buf, PAGE_SIZE, "%s %s\n",
-                       (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
-                        con->desc);
-
-}
-
-static struct device_attribute device_attrs[] = {
-       __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind),
-       __ATTR(name, S_IRUGO, show_name, NULL),
-};
-
-static int vtconsole_init_device(struct con_driver *con)
-{
-       int i;
-       int error = 0;
-
-       con->flag |= CON_DRIVER_FLAG_ATTR;
-       dev_set_drvdata(con->dev, con);
-       for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
-               error = device_create_file(con->dev, &device_attrs[i]);
-               if (error)
-                       break;
-       }
-
-       if (error) {
-               while (--i >= 0)
-                       device_remove_file(con->dev, &device_attrs[i]);
-               con->flag &= ~CON_DRIVER_FLAG_ATTR;
-       }
-
-       return error;
-}
-
-static void vtconsole_deinit_device(struct con_driver *con)
-{
-       int i;
-
-       if (con->flag & CON_DRIVER_FLAG_ATTR) {
-               for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
-                       device_remove_file(con->dev, &device_attrs[i]);
-               con->flag &= ~CON_DRIVER_FLAG_ATTR;
-       }
-}
-
-/**
- * con_is_bound - checks if driver is bound to the console
- * @csw: console driver
- *
- * RETURNS: zero if unbound, nonzero if bound
- *
- * Drivers can call this and if zero, they should release
- * all resources allocated on con_startup()
- */
-int con_is_bound(const struct consw *csw)
-{
-       int i, bound = 0;
-
-       for (i = 0; i < MAX_NR_CONSOLES; i++) {
-               if (con_driver_map[i] == csw) {
-                       bound = 1;
-                       break;
-               }
-       }
-
-       return bound;
-}
-EXPORT_SYMBOL(con_is_bound);
-
-/**
- * con_debug_enter - prepare the console for the kernel debugger
- * @sw: console driver
- *
- * Called when the console is taken over by the kernel debugger, this
- * function needs to save the current console state, then put the console
- * into a state suitable for the kernel debugger.
- *
- * RETURNS:
- * Zero on success, nonzero if a failure occurred when trying to prepare
- * the console for the debugger.
- */
-int con_debug_enter(struct vc_data *vc)
-{
-       int ret = 0;
-
-       saved_fg_console = fg_console;
-       saved_last_console = last_console;
-       saved_want_console = want_console;
-       saved_vc_mode = vc->vc_mode;
-       saved_console_blanked = console_blanked;
-       vc->vc_mode = KD_TEXT;
-       console_blanked = 0;
-       if (vc->vc_sw->con_debug_enter)
-               ret = vc->vc_sw->con_debug_enter(vc);
-#ifdef CONFIG_KGDB_KDB
-       /* Set the initial LINES variable if it is not already set */
-       if (vc->vc_rows < 999) {
-               int linecount;
-               char lns[4];
-               const char *setargs[3] = {
-                       "set",
-                       "LINES",
-                       lns,
-               };
-               if (kdbgetintenv(setargs[0], &linecount)) {
-                       snprintf(lns, 4, "%i", vc->vc_rows);
-                       kdb_set(2, setargs);
-               }
-       }
-#endif /* CONFIG_KGDB_KDB */
-       return ret;
-}
-EXPORT_SYMBOL_GPL(con_debug_enter);
-
-/**
- * con_debug_leave - restore console state
- * @sw: console driver
- *
- * Restore the console state to what it was before the kernel debugger
- * was invoked.
- *
- * RETURNS:
- * Zero on success, nonzero if a failure occurred when trying to restore
- * the console.
- */
-int con_debug_leave(void)
-{
-       struct vc_data *vc;
-       int ret = 0;
-
-       fg_console = saved_fg_console;
-       last_console = saved_last_console;
-       want_console = saved_want_console;
-       console_blanked = saved_console_blanked;
-       vc_cons[fg_console].d->vc_mode = saved_vc_mode;
-
-       vc = vc_cons[fg_console].d;
-       if (vc->vc_sw->con_debug_leave)
-               ret = vc->vc_sw->con_debug_leave(vc);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(con_debug_leave);
-
-/**
- * register_con_driver - register console driver to console layer
- * @csw: console driver
- * @first: the first console to take over, minimum value is 0
- * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
- *
- * DESCRIPTION: This function registers a console driver which can later
- * bind to a range of consoles specified by @first and @last. It will
- * also initialize the console driver by calling con_startup().
- */
-int register_con_driver(const struct consw *csw, int first, int last)
-{
-       struct module *owner = csw->owner;
-       struct con_driver *con_driver;
-       const char *desc;
-       int i, retval = 0;
-
-       if (!try_module_get(owner))
-               return -ENODEV;
-
-       acquire_console_sem();
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_driver = &registered_con_driver[i];
-
-               /* already registered */
-               if (con_driver->con == csw)
-                       retval = -EINVAL;
-       }
-
-       if (retval)
-               goto err;
-
-       desc = csw->con_startup();
-
-       if (!desc)
-               goto err;
-
-       retval = -EINVAL;
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == NULL) {
-                       con_driver->con = csw;
-                       con_driver->desc = desc;
-                       con_driver->node = i;
-                       con_driver->flag = CON_DRIVER_FLAG_MODULE |
-                                          CON_DRIVER_FLAG_INIT;
-                       con_driver->first = first;
-                       con_driver->last = last;
-                       retval = 0;
-                       break;
-               }
-       }
-
-       if (retval)
-               goto err;
-
-       con_driver->dev = device_create(vtconsole_class, NULL,
-                                               MKDEV(0, con_driver->node),
-                                               NULL, "vtcon%i",
-                                               con_driver->node);
-
-       if (IS_ERR(con_driver->dev)) {
-               printk(KERN_WARNING "Unable to create device for %s; "
-                      "errno = %ld\n", con_driver->desc,
-                      PTR_ERR(con_driver->dev));
-               con_driver->dev = NULL;
-       } else {
-               vtconsole_init_device(con_driver);
-       }
-
-err:
-       release_console_sem();
-       module_put(owner);
-       return retval;
-}
-EXPORT_SYMBOL(register_con_driver);
-
-/**
- * unregister_con_driver - unregister console driver from console layer
- * @csw: console driver
- *
- * DESCRIPTION: All drivers that registers to the console layer must
- * call this function upon exit, or if the console driver is in a state
- * where it won't be able to handle console services, such as the
- * framebuffer console without loaded framebuffer drivers.
- *
- * The driver must unbind first prior to unregistration.
- */
-int unregister_con_driver(const struct consw *csw)
-{
-       int i, retval = -ENODEV;
-
-       acquire_console_sem();
-
-       /* cannot unregister a bound driver */
-       if (con_is_bound(csw))
-               goto err;
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               struct con_driver *con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == csw &&
-                   con_driver->flag & CON_DRIVER_FLAG_MODULE) {
-                       vtconsole_deinit_device(con_driver);
-                       device_destroy(vtconsole_class,
-                                      MKDEV(0, con_driver->node));
-                       con_driver->con = NULL;
-                       con_driver->desc = NULL;
-                       con_driver->dev = NULL;
-                       con_driver->node = 0;
-                       con_driver->flag = 0;
-                       con_driver->first = 0;
-                       con_driver->last = 0;
-                       retval = 0;
-                       break;
-               }
-       }
-err:
-       release_console_sem();
-       return retval;
-}
-EXPORT_SYMBOL(unregister_con_driver);
-
-/*
- *     If we support more console drivers, this function is used
- *     when a driver wants to take over some existing consoles
- *     and become default driver for newly opened ones.
- *
- *      take_over_console is basically a register followed by unbind
- */
-int take_over_console(const struct consw *csw, int first, int last, int deflt)
-{
-       int err;
-
-       err = register_con_driver(csw, first, last);
-
-       if (!err)
-               bind_con_driver(csw, first, last, deflt);
-
-       return err;
-}
-
-/*
- * give_up_console is a wrapper to unregister_con_driver. It will only
- * work if driver is fully unbound.
- */
-void give_up_console(const struct consw *csw)
-{
-       unregister_con_driver(csw);
-}
-
-static int __init vtconsole_class_init(void)
-{
-       int i;
-
-       vtconsole_class = class_create(THIS_MODULE, "vtconsole");
-       if (IS_ERR(vtconsole_class)) {
-               printk(KERN_WARNING "Unable to create vt console class; "
-                      "errno = %ld\n", PTR_ERR(vtconsole_class));
-               vtconsole_class = NULL;
-       }
-
-       /* Add system drivers to sysfs */
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               struct con_driver *con = &registered_con_driver[i];
-
-               if (con->con && !con->dev) {
-                       con->dev = device_create(vtconsole_class, NULL,
-                                                        MKDEV(0, con->node),
-                                                        NULL, "vtcon%i",
-                                                        con->node);
-
-                       if (IS_ERR(con->dev)) {
-                               printk(KERN_WARNING "Unable to create "
-                                      "device for %s; errno = %ld\n",
-                                      con->desc, PTR_ERR(con->dev));
-                               con->dev = NULL;
-                       } else {
-                               vtconsole_init_device(con);
-                       }
-               }
-       }
-
-       return 0;
-}
-postcore_initcall(vtconsole_class_init);
-
-#endif
-
-/*
- *     Screen blanking
- */
-
-static int set_vesa_blanking(char __user *p)
-{
-       unsigned int mode;
-
-       if (get_user(mode, p + 1))
-               return -EFAULT;
-
-       vesa_blank_mode = (mode < 4) ? mode : 0;
-       return 0;
-}
-
-void do_blank_screen(int entering_gfx)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-       int i;
-
-       WARN_CONSOLE_UNLOCKED();
-
-       if (console_blanked) {
-               if (blank_state == blank_vesa_wait) {
-                       blank_state = blank_off;
-                       vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0);
-               }
-               return;
-       }
-
-       /* entering graphics mode? */
-       if (entering_gfx) {
-               hide_cursor(vc);
-               save_screen(vc);
-               vc->vc_sw->con_blank(vc, -1, 1);
-               console_blanked = fg_console + 1;
-               blank_state = blank_off;
-               set_origin(vc);
-               return;
-       }
-
-       if (blank_state != blank_normal_wait)
-               return;
-       blank_state = blank_off;
-
-       /* don't blank graphics */
-       if (vc->vc_mode != KD_TEXT) {
-               console_blanked = fg_console + 1;
-               return;
-       }
-
-       hide_cursor(vc);
-       del_timer_sync(&console_timer);
-       blank_timer_expired = 0;
-
-       save_screen(vc);
-       /* In case we need to reset origin, blanking hook returns 1 */
-       i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0);
-       console_blanked = fg_console + 1;
-       if (i)
-               set_origin(vc);
-
-       if (console_blank_hook && console_blank_hook(1))
-               return;
-
-       if (vesa_off_interval && vesa_blank_mode) {
-               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);
-
-/*
- * Called by timer as well as from vt_console_driver
- */
-void do_unblank_screen(int leaving_gfx)
-{
-       struct vc_data *vc;
-
-       /* This should now always be called from a "sane" (read: can schedule)
-        * context for the sake of the low level drivers, except in the special
-        * case of oops_in_progress
-        */
-       if (!oops_in_progress)
-               might_sleep();
-
-       WARN_CONSOLE_UNLOCKED();
-
-       ignore_poke = 0;
-       if (!console_blanked)
-               return;
-       if (!vc_cons_allocated(fg_console)) {
-               /* impossible */
-               printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
-               return;
-       }
-       vc = vc_cons[fg_console].d;
-       /* Try to unblank in oops case too */
-       if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc))
-               return; /* but leave console_blanked != 0 */
-
-       if (blankinterval) {
-               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-               blank_state = blank_normal_wait;
-       }
-
-       console_blanked = 0;
-       if (vc->vc_sw->con_blank(vc, 0, leaving_gfx) || vt_force_oops_output(vc))
-               /* Low-level driver cannot restore -> do it ourselves */
-               update_screen(vc);
-       if (console_blank_hook)
-               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);
-
-/*
- * This is called by the outside world to cause a forced unblank, mostly for
- * oopses. Currently, I just call do_unblank_screen(0), but we could eventually
- * call it with 1 as an argument and so force a mode restore... that may kill
- * X or at least garbage the screen but would also make the Oops visible...
- */
-void unblank_screen(void)
-{
-       do_unblank_screen(0);
-}
-
-/*
- * We defer the timer blanking to work queue so it can take the console mutex
- * (console operations can still happen at irq time, but only from printk which
- * has the console mutex. Not perfect yet, but better than no locking
- */
-static void blank_screen_t(unsigned long dummy)
-{
-       if (unlikely(!keventd_up())) {
-               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-               return;
-       }
-       blank_timer_expired = 1;
-       schedule_work(&console_work);
-}
-
-void poke_blanked_console(void)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       /* Add this so we quickly catch whoever might call us in a non
-        * safe context. Nowadays, unblank_screen() isn't to be called in
-        * atomic contexts and is allowed to schedule (with the special case
-        * of oops_in_progress, but that isn't of any concern for this
-        * function. --BenH.
-        */
-       might_sleep();
-
-       /* This isn't perfectly race free, but a race here would be mostly harmless,
-        * at worse, we'll do a spurrious blank and it's unlikely
-        */
-       del_timer(&console_timer);
-       blank_timer_expired = 0;
-
-       if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS)
-               return;
-       if (console_blanked)
-               unblank_screen();
-       else if (blankinterval) {
-               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-               blank_state = blank_normal_wait;
-       }
-}
-
-/*
- *     Palettes
- */
-
-static void set_palette(struct vc_data *vc)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (vc->vc_mode != KD_GRAPHICS)
-               vc->vc_sw->con_set_palette(vc, color_table);
-}
-
-static int set_get_cmap(unsigned char __user *arg, int set)
-{
-    int i, j, k;
-
-    WARN_CONSOLE_UNLOCKED();
-
-    for (i = 0; i < 16; i++)
-       if (set) {
-           get_user(default_red[i], arg++);
-           get_user(default_grn[i], arg++);
-           get_user(default_blu[i], arg++);
-       } else {
-           put_user(default_red[i], arg++);
-           put_user(default_grn[i], arg++);
-           put_user(default_blu[i], arg++);
-       }
-    if (set) {
-       for (i = 0; i < MAX_NR_CONSOLES; i++)
-           if (vc_cons_allocated(i)) {
-               for (j = k = 0; j < 16; j++) {
-                   vc_cons[i].d->vc_palette[k++] = default_red[j];
-                   vc_cons[i].d->vc_palette[k++] = default_grn[j];
-                   vc_cons[i].d->vc_palette[k++] = default_blu[j];
-               }
-               set_palette(vc_cons[i].d);
-           }
-    }
-    return 0;
-}
-
-/*
- * Load palette into the DAC registers. arg points to a colour
- * map, 3 bytes per colour, 16 colours, range from 0 to 255.
- */
-
-int con_set_cmap(unsigned char __user *arg)
-{
-       int rc;
-
-       acquire_console_sem();
-       rc = set_get_cmap (arg,1);
-       release_console_sem();
-
-       return rc;
-}
-
-int con_get_cmap(unsigned char __user *arg)
-{
-       int rc;
-
-       acquire_console_sem();
-       rc = set_get_cmap (arg,0);
-       release_console_sem();
-
-       return rc;
-}
-
-void reset_palette(struct vc_data *vc)
-{
-       int j, k;
-       for (j=k=0; j<16; j++) {
-               vc->vc_palette[k++] = default_red[j];
-               vc->vc_palette[k++] = default_grn[j];
-               vc->vc_palette[k++] = default_blu[j];
-       }
-       set_palette(vc);
-}
-
-/*
- *  Font switching
- *
- *  Currently we only support fonts up to 32 pixels wide, at a maximum height
- *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, 
- *  depending on width) reserved for each character which is kinda wasty, but 
- *  this is done in order to maintain compatibility with the EGA/VGA fonts. It 
- *  is upto the actual low-level console-driver convert data into its favorite
- *  format (maybe we should add a `fontoffset' field to the `display'
- *  structure so we won't have to convert the fontdata all the time.
- *  /Jes
- */
-
-#define max_font_size 65536
-
-static int con_font_get(struct vc_data *vc, struct console_font_op *op)
-{
-       struct console_font font;
-       int rc = -EINVAL;
-       int c;
-
-       if (vc->vc_mode != KD_TEXT)
-               return -EINVAL;
-
-       if (op->data) {
-               font.data = kmalloc(max_font_size, GFP_KERNEL);
-               if (!font.data)
-                       return -ENOMEM;
-       } else
-               font.data = NULL;
-
-       acquire_console_sem();
-       if (vc->vc_sw->con_font_get)
-               rc = vc->vc_sw->con_font_get(vc, &font);
-       else
-               rc = -ENOSYS;
-       release_console_sem();
-
-       if (rc)
-               goto out;
-
-       c = (font.width+7)/8 * 32 * font.charcount;
-
-       if (op->data && font.charcount > op->charcount)
-               rc = -ENOSPC;
-       if (!(op->flags & KD_FONT_FLAG_OLD)) {
-               if (font.width > op->width || font.height > op->height) 
-                       rc = -ENOSPC;
-       } else {
-               if (font.width != 8)
-                       rc = -EIO;
-               else if ((op->height && font.height > op->height) ||
-                        font.height > 32)
-                       rc = -ENOSPC;
-       }
-       if (rc)
-               goto out;
-
-       op->height = font.height;
-       op->width = font.width;
-       op->charcount = font.charcount;
-
-       if (op->data && copy_to_user(op->data, font.data, c))
-               rc = -EFAULT;
-
-out:
-       kfree(font.data);
-       return rc;
-}
-
-static int con_font_set(struct vc_data *vc, struct console_font_op *op)
-{
-       struct console_font font;
-       int rc = -EINVAL;
-       int size;
-
-       if (vc->vc_mode != KD_TEXT)
-               return -EINVAL;
-       if (!op->data)
-               return -EINVAL;
-       if (op->charcount > 512)
-               return -EINVAL;
-       if (!op->height) {              /* Need to guess font height [compat] */
-               int h, i;
-               u8 __user *charmap = op->data;
-               u8 tmp;
-               
-               /* If from KDFONTOP ioctl, don't allow things which can be done in userland,
-                  so that we can get rid of this soon */
-               if (!(op->flags & KD_FONT_FLAG_OLD))
-                       return -EINVAL;
-               for (h = 32; h > 0; h--)
-                       for (i = 0; i < op->charcount; i++) {
-                               if (get_user(tmp, &charmap[32*i+h-1]))
-                                       return -EFAULT;
-                               if (tmp)
-                                       goto nonzero;
-                       }
-               return -EINVAL;
-       nonzero:
-               op->height = h;
-       }
-       if (op->width <= 0 || op->width > 32 || op->height > 32)
-               return -EINVAL;
-       size = (op->width+7)/8 * 32 * op->charcount;
-       if (size > max_font_size)
-               return -ENOSPC;
-       font.charcount = op->charcount;
-       font.height = op->height;
-       font.width = op->width;
-       font.data = memdup_user(op->data, size);
-       if (IS_ERR(font.data))
-               return PTR_ERR(font.data);
-       acquire_console_sem();
-       if (vc->vc_sw->con_font_set)
-               rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
-       else
-               rc = -ENOSYS;
-       release_console_sem();
-       kfree(font.data);
-       return rc;
-}
-
-static int con_font_default(struct vc_data *vc, struct console_font_op *op)
-{
-       struct console_font font = {.width = op->width, .height = op->height};
-       char name[MAX_FONT_NAME];
-       char *s = name;
-       int rc;
-
-       if (vc->vc_mode != KD_TEXT)
-               return -EINVAL;
-
-       if (!op->data)
-               s = NULL;
-       else if (strncpy_from_user(name, op->data, MAX_FONT_NAME - 1) < 0)
-               return -EFAULT;
-       else
-               name[MAX_FONT_NAME - 1] = 0;
-
-       acquire_console_sem();
-       if (vc->vc_sw->con_font_default)
-               rc = vc->vc_sw->con_font_default(vc, &font, s);
-       else
-               rc = -ENOSYS;
-       release_console_sem();
-       if (!rc) {
-               op->width = font.width;
-               op->height = font.height;
-       }
-       return rc;
-}
-
-static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
-{
-       int con = op->height;
-       int rc;
-
-       if (vc->vc_mode != KD_TEXT)
-               return -EINVAL;
-
-       acquire_console_sem();
-       if (!vc->vc_sw->con_font_copy)
-               rc = -ENOSYS;
-       else if (con < 0 || !vc_cons_allocated(con))
-               rc = -ENOTTY;
-       else if (con == vc->vc_num)     /* nothing to do */
-               rc = 0;
-       else
-               rc = vc->vc_sw->con_font_copy(vc, con);
-       release_console_sem();
-       return rc;
-}
-
-int con_font_op(struct vc_data *vc, struct console_font_op *op)
-{
-       switch (op->op) {
-       case KD_FONT_OP_SET:
-               return con_font_set(vc, op);
-       case KD_FONT_OP_GET:
-               return con_font_get(vc, op);
-       case KD_FONT_OP_SET_DEFAULT:
-               return con_font_default(vc, op);
-       case KD_FONT_OP_COPY:
-               return con_font_copy(vc, op);
-       }
-       return -ENOSYS;
-}
-
-/*
- *     Interface exported to selection and vcs.
- */
-
-/* used by selection */
-u16 screen_glyph(struct vc_data *vc, int offset)
-{
-       u16 w = scr_readw(screenpos(vc, offset, 1));
-       u16 c = w & 0xff;
-
-       if (w & vc->vc_hi_font_mask)
-               c |= 0x100;
-       return c;
-}
-EXPORT_SYMBOL_GPL(screen_glyph);
-
-/* used by vcs - note the word offset */
-unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
-{
-       return screenpos(vc, 2 * w_offset, viewed);
-}
-
-void getconsxy(struct vc_data *vc, unsigned char *p)
-{
-       p[0] = vc->vc_x;
-       p[1] = vc->vc_y;
-}
-
-void putconsxy(struct vc_data *vc, unsigned char *p)
-{
-       hide_cursor(vc);
-       gotoxy(vc, p[0], p[1]);
-       set_cursor(vc);
-}
-
-u16 vcs_scr_readw(struct vc_data *vc, const u16 *org)
-{
-       if ((unsigned long)org == vc->vc_pos && softcursor_original != -1)
-               return softcursor_original;
-       return scr_readw(org);
-}
-
-void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org)
-{
-       scr_writew(val, org);
-       if ((unsigned long)org == vc->vc_pos) {
-               softcursor_original = -1;
-               add_softcursor(vc);
-       }
-}
-
-void vcs_scr_updated(struct vc_data *vc)
-{
-       notify_update(vc);
-}
-
-/*
- *     Visible symbols for modules
- */
-
-EXPORT_SYMBOL(color_table);
-EXPORT_SYMBOL(default_red);
-EXPORT_SYMBOL(default_grn);
-EXPORT_SYMBOL(default_blu);
-EXPORT_SYMBOL(update_region);
-EXPORT_SYMBOL(redraw_screen);
-EXPORT_SYMBOL(vc_resize);
-EXPORT_SYMBOL(fg_console);
-EXPORT_SYMBOL(console_blank_hook);
-EXPORT_SYMBOL(console_blanked);
-EXPORT_SYMBOL(vc_cons);
-EXPORT_SYMBOL(global_cursor_default);
-#ifndef VT_SINGLE_DRIVER
-EXPORT_SYMBOL(take_over_console);
-EXPORT_SYMBOL(give_up_console);
-#endif
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
deleted file mode 100644 (file)
index 6b68a0f..0000000
+++ /dev/null
@@ -1,1788 +0,0 @@
-/*
- *  linux/drivers/char/vt_ioctl.c
- *
- *  Copyright (C) 1992 obz under the linux copyright
- *
- *  Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
- *  Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
- *  Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995
- *  Some code moved for less code duplication - Andi Kleen - Mar 1997
- *  Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/timer.h>
-#include <linux/kernel.h>
-#include <linux/compat.h>
-#include <linux/module.h>
-#include <linux/kd.h>
-#include <linux/vt.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/major.h>
-#include <linux/fs.h>
-#include <linux/console.h>
-#include <linux/consolemap.h>
-#include <linux/signal.h>
-#include <linux/smp_lock.h>
-#include <linux/timex.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/kbd_diacr.h>
-#include <linux/selection.h>
-
-char vt_dont_switch;
-extern struct tty_driver *console_driver;
-
-#define VT_IS_IN_USE(i)        (console_driver->ttys[i] && console_driver->ttys[i]->count)
-#define VT_BUSY(i)     (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons)
-
-/*
- * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
- * experimentation and study of X386 SYSV handling.
- *
- * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
- * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
- * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
- * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to
- * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using
- * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing
- * to the current console is done by the main ioctl code.
- */
-
-#ifdef CONFIG_X86
-#include <linux/syscalls.h>
-#endif
-
-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.oldev = old + 1;
-               ve->event.newev = 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_tty(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.newev != n);
-       return 0;
-}
-
-/*
- * these are the valid i/o ports we're allowed to change. they map all the
- * video ports
- */
-#define GPFIRST 0x3b4
-#define GPLAST 0x3df
-#define GPNUM (GPLAST - GPFIRST + 1)
-
-#define i (tmp.kb_index)
-#define s (tmp.kb_table)
-#define v (tmp.kb_value)
-static inline int
-do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd)
-{
-       struct kbentry tmp;
-       ushort *key_map, val, ov;
-
-       if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
-               return -EFAULT;
-
-       if (!capable(CAP_SYS_TTY_CONFIG))
-               perm = 0;
-
-       switch (cmd) {
-       case KDGKBENT:
-               key_map = key_maps[s];
-               if (key_map) {
-                   val = U(key_map[i]);
-                   if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
-                       val = K_HOLE;
-               } else
-                   val = (i ? K_HOLE : K_NOSUCHMAP);
-               return put_user(val, &user_kbe->kb_value);
-       case KDSKBENT:
-               if (!perm)
-                       return -EPERM;
-               if (!i && v == K_NOSUCHMAP) {
-                       /* deallocate map */
-                       key_map = key_maps[s];
-                       if (s && key_map) {
-                           key_maps[s] = NULL;
-                           if (key_map[0] == U(K_ALLOCATED)) {
-                                       kfree(key_map);
-                                       keymap_count--;
-                           }
-                       }
-                       break;
-               }
-
-               if (KTYP(v) < NR_TYPES) {
-                   if (KVAL(v) > max_vals[KTYP(v)])
-                               return -EINVAL;
-               } else
-                   if (kbd->kbdmode != VC_UNICODE)
-                               return -EINVAL;
-
-               /* ++Geert: non-PC keyboards may generate keycode zero */
-#if !defined(__mc68000__) && !defined(__powerpc__)
-               /* assignment to entry 0 only tests validity of args */
-               if (!i)
-                       break;
-#endif
-
-               if (!(key_map = key_maps[s])) {
-                       int j;
-
-                       if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
-                           !capable(CAP_SYS_RESOURCE))
-                               return -EPERM;
-
-                       key_map = kmalloc(sizeof(plain_map),
-                                                    GFP_KERNEL);
-                       if (!key_map)
-                               return -ENOMEM;
-                       key_maps[s] = key_map;
-                       key_map[0] = U(K_ALLOCATED);
-                       for (j = 1; j < NR_KEYS; j++)
-                               key_map[j] = U(K_HOLE);
-                       keymap_count++;
-               }
-               ov = U(key_map[i]);
-               if (v == ov)
-                       break;  /* nothing to do */
-               /*
-                * Attention Key.
-                */
-               if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               key_map[i] = U(v);
-               if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
-                       compute_shiftstate();
-               break;
-       }
-       return 0;
-}
-#undef i
-#undef s
-#undef v
-
-static inline int 
-do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm)
-{
-       struct kbkeycode tmp;
-       int kc = 0;
-
-       if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
-               return -EFAULT;
-       switch (cmd) {
-       case KDGETKEYCODE:
-               kc = getkeycode(tmp.scancode);
-               if (kc >= 0)
-                       kc = put_user(kc, &user_kbkc->keycode);
-               break;
-       case KDSETKEYCODE:
-               if (!perm)
-                       return -EPERM;
-               kc = setkeycode(tmp.scancode, tmp.keycode);
-               break;
-       }
-       return kc;
-}
-
-static inline int
-do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
-{
-       struct kbsentry *kbs;
-       char *p;
-       u_char *q;
-       u_char __user *up;
-       int sz;
-       int delta;
-       char *first_free, *fj, *fnw;
-       int i, j, k;
-       int ret;
-
-       if (!capable(CAP_SYS_TTY_CONFIG))
-               perm = 0;
-
-       kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
-       if (!kbs) {
-               ret = -ENOMEM;
-               goto reterr;
-       }
-
-       /* we mostly copy too much here (512bytes), but who cares ;) */
-       if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
-               ret = -EFAULT;
-               goto reterr;
-       }
-       kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
-       i = kbs->kb_func;
-
-       switch (cmd) {
-       case KDGKBSENT:
-               sz = sizeof(kbs->kb_string) - 1; /* sz should have been
-                                                 a struct member */
-               up = user_kdgkb->kb_string;
-               p = func_table[i];
-               if(p)
-                       for ( ; *p && sz; p++, sz--)
-                               if (put_user(*p, up++)) {
-                                       ret = -EFAULT;
-                                       goto reterr;
-                               }
-               if (put_user('\0', up)) {
-                       ret = -EFAULT;
-                       goto reterr;
-               }
-               kfree(kbs);
-               return ((p && *p) ? -EOVERFLOW : 0);
-       case KDSKBSENT:
-               if (!perm) {
-                       ret = -EPERM;
-                       goto reterr;
-               }
-
-               q = func_table[i];
-               first_free = funcbufptr + (funcbufsize - funcbufleft);
-               for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) 
-                       ;
-               if (j < MAX_NR_FUNC)
-                       fj = func_table[j];
-               else
-                       fj = first_free;
-
-               delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
-               if (delta <= funcbufleft) {     /* it fits in current buf */
-                   if (j < MAX_NR_FUNC) {
-                       memmove(fj + delta, fj, first_free - fj);
-                       for (k = j; k < MAX_NR_FUNC; k++)
-                           if (func_table[k])
-                               func_table[k] += delta;
-                   }
-                   if (!q)
-                     func_table[i] = fj;
-                   funcbufleft -= delta;
-               } else {                        /* allocate a larger buffer */
-                   sz = 256;
-                   while (sz < funcbufsize - funcbufleft + delta)
-                     sz <<= 1;
-                   fnw = kmalloc(sz, GFP_KERNEL);
-                   if(!fnw) {
-                     ret = -ENOMEM;
-                     goto reterr;
-                   }
-
-                   if (!q)
-                     func_table[i] = fj;
-                   if (fj > funcbufptr)
-                       memmove(fnw, funcbufptr, fj - funcbufptr);
-                   for (k = 0; k < j; k++)
-                     if (func_table[k])
-                       func_table[k] = fnw + (func_table[k] - funcbufptr);
-
-                   if (first_free > fj) {
-                       memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
-                       for (k = j; k < MAX_NR_FUNC; k++)
-                         if (func_table[k])
-                           func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
-                   }
-                   if (funcbufptr != func_buf)
-                     kfree(funcbufptr);
-                   funcbufptr = fnw;
-                   funcbufleft = funcbufleft - delta + sz - funcbufsize;
-                   funcbufsize = sz;
-               }
-               strcpy(func_table[i], kbs->kb_string);
-               break;
-       }
-       ret = 0;
-reterr:
-       kfree(kbs);
-       return ret;
-}
-
-static inline int 
-do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op)
-{
-       struct consolefontdesc cfdarg;
-       int i;
-
-       if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) 
-               return -EFAULT;
-       
-       switch (cmd) {
-       case PIO_FONTX:
-               if (!perm)
-                       return -EPERM;
-               op->op = KD_FONT_OP_SET;
-               op->flags = KD_FONT_FLAG_OLD;
-               op->width = 8;
-               op->height = cfdarg.charheight;
-               op->charcount = cfdarg.charcount;
-               op->data = cfdarg.chardata;
-               return con_font_op(vc_cons[fg_console].d, op);
-       case GIO_FONTX: {
-               op->op = KD_FONT_OP_GET;
-               op->flags = KD_FONT_FLAG_OLD;
-               op->width = 8;
-               op->height = cfdarg.charheight;
-               op->charcount = cfdarg.charcount;
-               op->data = cfdarg.chardata;
-               i = con_font_op(vc_cons[fg_console].d, op);
-               if (i)
-                       return i;
-               cfdarg.charheight = op->height;
-               cfdarg.charcount = op->charcount;
-               if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc)))
-                       return -EFAULT;
-               return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-static inline int 
-do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc)
-{
-       struct unimapdesc tmp;
-
-       if (copy_from_user(&tmp, user_ud, sizeof tmp))
-               return -EFAULT;
-       if (tmp.entries)
-               if (!access_ok(VERIFY_WRITE, tmp.entries,
-                               tmp.entry_ct*sizeof(struct unipair)))
-                       return -EFAULT;
-       switch (cmd) {
-       case PIO_UNIMAP:
-               if (!perm)
-                       return -EPERM;
-               return con_set_unimap(vc, tmp.entry_ct, tmp.entries);
-       case GIO_UNIMAP:
-               if (!perm && fg_console != vc->vc_num)
-                       return -EPERM;
-               return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
-       }
-       return 0;
-}
-
-
-
-/*
- * We handle the console-specific ioctl's here.  We allow the
- * capability to modify any console, not just the fg_console. 
- */
-int vt_ioctl(struct tty_struct *tty, struct file * file,
-            unsigned int cmd, unsigned long arg)
-{
-       struct vc_data *vc = tty->driver_data;
-       struct console_font_op op;      /* used in multiple places here */
-       struct kbd_struct * kbd;
-       unsigned int console;
-       unsigned char ucval;
-       unsigned int uival;
-       void __user *up = (void __user *)arg;
-       int i, perm;
-       int ret = 0;
-
-       console = vc->vc_num;
-
-       tty_lock();
-
-       if (!vc_cons_allocated(console)) {      /* impossible? */
-               ret = -ENOIOCTLCMD;
-               goto out;
-       }
-
-
-       /*
-        * To have permissions to do most of the vt ioctls, we either have
-        * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
-        */
-       perm = 0;
-       if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
-               perm = 1;
-       kbd = kbd_table + console;
-       switch (cmd) {
-       case TIOCLINUX:
-               ret = tioclinux(tty, arg);
-               break;
-       case KIOCSOUND:
-               if (!perm)
-                       goto eperm;
-               /*
-                * The use of PIT_TICK_RATE is historic, it used to be
-                * the platform-dependent CLOCK_TICK_RATE between 2.6.12
-                * and 2.6.36, which was a minor but unfortunate ABI
-                * change.
-                */
-               if (arg)
-                       arg = PIT_TICK_RATE / arg;
-               kd_mksound(arg, 0);
-               break;
-
-       case KDMKTONE:
-               if (!perm)
-                       goto eperm;
-       {
-               unsigned int ticks, count;
-               
-               /*
-                * Generate the tone for the appropriate number of ticks.
-                * If the time is zero, turn off sound ourselves.
-                */
-               ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
-               count = ticks ? (arg & 0xffff) : 0;
-               if (count)
-                       count = PIT_TICK_RATE / count;
-               kd_mksound(count, ticks);
-               break;
-       }
-
-       case KDGKBTYPE:
-               /*
-                * this is naive.
-                */
-               ucval = KB_101;
-               goto setchar;
-
-               /*
-                * These cannot be implemented on any machine that implements
-                * ioperm() in user level (such as Alpha PCs) or not at all.
-                *
-                * XXX: you should never use these, just call ioperm directly..
-                */
-#ifdef CONFIG_X86
-       case KDADDIO:
-       case KDDELIO:
-               /*
-                * KDADDIO and KDDELIO may be able to add ports beyond what
-                * we reject here, but to be safe...
-                */
-               if (arg < GPFIRST || arg > GPLAST) {
-                       ret = -EINVAL;
-                       break;
-               }
-               ret = sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
-               break;
-
-       case KDENABIO:
-       case KDDISABIO:
-               ret = sys_ioperm(GPFIRST, GPNUM,
-                                 (cmd == KDENABIO)) ? -ENXIO : 0;
-               break;
-#endif
-
-       /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */
-               
-       case KDKBDREP:
-       {
-               struct kbd_repeat kbrep;
-               
-               if (!capable(CAP_SYS_TTY_CONFIG))
-                       goto eperm;
-
-               if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
-                       ret =  -EFAULT;
-                       break;
-               }
-               ret = kbd_rate(&kbrep);
-               if (ret)
-                       break;
-               if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat)))
-                       ret = -EFAULT;
-               break;
-       }
-
-       case KDSETMODE:
-               /*
-                * currently, setting the mode from KD_TEXT to KD_GRAPHICS
-                * doesn't do a whole lot. i'm not sure if it should do any
-                * restoration of modes or what...
-                *
-                * XXX It should at least call into the driver, fbdev's definitely
-                * need to restore their engine state. --BenH
-                */
-               if (!perm)
-                       goto eperm;
-               switch (arg) {
-               case KD_GRAPHICS:
-                       break;
-               case KD_TEXT0:
-               case KD_TEXT1:
-                       arg = KD_TEXT;
-               case KD_TEXT:
-                       break;
-               default:
-                       ret = -EINVAL;
-                       goto out;
-               }
-               if (vc->vc_mode == (unsigned char) arg)
-                       break;
-               vc->vc_mode = (unsigned char) arg;
-               if (console != fg_console)
-                       break;
-               /*
-                * explicitly blank/unblank the screen if switching modes
-                */
-               acquire_console_sem();
-               if (arg == KD_TEXT)
-                       do_unblank_screen(1);
-               else
-                       do_blank_screen(1);
-               release_console_sem();
-               break;
-
-       case KDGETMODE:
-               uival = vc->vc_mode;
-               goto setint;
-
-       case KDMAPDISP:
-       case KDUNMAPDISP:
-               /*
-                * these work like a combination of mmap and KDENABIO.
-                * this could be easily finished.
-                */
-               ret = -EINVAL;
-               break;
-
-       case KDSKBMODE:
-               if (!perm)
-                       goto eperm;
-               switch(arg) {
-                 case K_RAW:
-                       kbd->kbdmode = VC_RAW;
-                       break;
-                 case K_MEDIUMRAW:
-                       kbd->kbdmode = VC_MEDIUMRAW;
-                       break;
-                 case K_XLATE:
-                       kbd->kbdmode = VC_XLATE;
-                       compute_shiftstate();
-                       break;
-                 case K_UNICODE:
-                       kbd->kbdmode = VC_UNICODE;
-                       compute_shiftstate();
-                       break;
-                 default:
-                       ret = -EINVAL;
-                       goto out;
-               }
-               tty_ldisc_flush(tty);
-               break;
-
-       case KDGKBMODE:
-               uival = ((kbd->kbdmode == VC_RAW) ? K_RAW :
-                                (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
-                                (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
-                                K_XLATE);
-               goto setint;
-
-       /* this could be folded into KDSKBMODE, but for compatibility
-          reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
-       case KDSKBMETA:
-               switch(arg) {
-                 case K_METABIT:
-                       clr_vc_kbd_mode(kbd, VC_META);
-                       break;
-                 case K_ESCPREFIX:
-                       set_vc_kbd_mode(kbd, VC_META);
-                       break;
-                 default:
-                       ret = -EINVAL;
-               }
-               break;
-
-       case KDGKBMETA:
-               uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
-       setint:
-               ret = put_user(uival, (int __user *)arg);
-               break;
-
-       case KDGETKEYCODE:
-       case KDSETKEYCODE:
-               if(!capable(CAP_SYS_TTY_CONFIG))
-                       perm = 0;
-               ret = do_kbkeycode_ioctl(cmd, up, perm);
-               break;
-
-       case KDGKBENT:
-       case KDSKBENT:
-               ret = do_kdsk_ioctl(cmd, up, perm, kbd);
-               break;
-
-       case KDGKBSENT:
-       case KDSKBSENT:
-               ret = do_kdgkb_ioctl(cmd, up, perm);
-               break;
-
-       case KDGKBDIACR:
-       {
-               struct kbdiacrs __user *a = up;
-               struct kbdiacr diacr;
-               int i;
-
-               if (put_user(accent_table_size, &a->kb_cnt)) {
-                       ret = -EFAULT;
-                       break;
-               }
-               for (i = 0; i < accent_table_size; i++) {
-                       diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
-                       diacr.base = conv_uni_to_8bit(accent_table[i].base);
-                       diacr.result = conv_uni_to_8bit(accent_table[i].result);
-                       if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
-                               ret = -EFAULT;
-                               break;
-                       }
-               }
-               break;
-       }
-       case KDGKBDIACRUC:
-       {
-               struct kbdiacrsuc __user *a = up;
-
-               if (put_user(accent_table_size, &a->kb_cnt))
-                       ret = -EFAULT;
-               else if (copy_to_user(a->kbdiacruc, accent_table,
-                               accent_table_size*sizeof(struct kbdiacruc)))
-                       ret = -EFAULT;
-               break;
-       }
-
-       case KDSKBDIACR:
-       {
-               struct kbdiacrs __user *a = up;
-               struct kbdiacr diacr;
-               unsigned int ct;
-               int i;
-
-               if (!perm)
-                       goto eperm;
-               if (get_user(ct,&a->kb_cnt)) {
-                       ret = -EFAULT;
-                       break;
-               }
-               if (ct >= MAX_DIACR) {
-                       ret = -EINVAL;
-                       break;
-               }
-               accent_table_size = ct;
-               for (i = 0; i < ct; i++) {
-                       if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
-                               ret = -EFAULT;
-                               break;
-                       }
-                       accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
-                       accent_table[i].base = conv_8bit_to_uni(diacr.base);
-                       accent_table[i].result = conv_8bit_to_uni(diacr.result);
-               }
-               break;
-       }
-
-       case KDSKBDIACRUC:
-       {
-               struct kbdiacrsuc __user *a = up;
-               unsigned int ct;
-
-               if (!perm)
-                       goto eperm;
-               if (get_user(ct,&a->kb_cnt)) {
-                       ret = -EFAULT;
-                       break;
-               }
-               if (ct >= MAX_DIACR) {
-                       ret = -EINVAL;
-                       break;
-               }
-               accent_table_size = ct;
-               if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
-                       ret = -EFAULT;
-               break;
-       }
-
-       /* the ioctls below read/set the flags usually shown in the leds */
-       /* don't use them - they will go away without warning */
-       case KDGKBLED:
-               ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
-               goto setchar;
-
-       case KDSKBLED:
-               if (!perm)
-                       goto eperm;
-               if (arg & ~0x77) {
-                       ret = -EINVAL;
-                       break;
-               }
-               kbd->ledflagstate = (arg & 7);
-               kbd->default_ledflagstate = ((arg >> 4) & 7);
-               set_leds();
-               break;
-
-       /* the ioctls below only set the lights, not the functions */
-       /* for those, see KDGKBLED and KDSKBLED above */
-       case KDGETLED:
-               ucval = getledstate();
-       setchar:
-               ret = put_user(ucval, (char __user *)arg);
-               break;
-
-       case KDSETLED:
-               if (!perm)
-                       goto eperm;
-               setledstate(kbd, arg);
-               break;
-
-       /*
-        * A process can indicate its willingness to accept signals
-        * generated by pressing an appropriate key combination.
-        * Thus, one can have a daemon that e.g. spawns a new console
-        * upon a keypress and then changes to it.
-        * See also the kbrequest field of inittab(5).
-        */
-       case KDSIGACCEPT:
-       {
-               if (!perm || !capable(CAP_KILL))
-                       goto eperm;
-               if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
-                       ret = -EINVAL;
-               else {
-                       spin_lock_irq(&vt_spawn_con.lock);
-                       put_pid(vt_spawn_con.pid);
-                       vt_spawn_con.pid = get_pid(task_pid(current));
-                       vt_spawn_con.sig = arg;
-                       spin_unlock_irq(&vt_spawn_con.lock);
-               }
-               break;
-       }
-
-       case VT_SETMODE:
-       {
-               struct vt_mode tmp;
-
-               if (!perm)
-                       goto eperm;
-               if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-               acquire_console_sem();
-               vc->vt_mode = tmp;
-               /* the frsig is ignored, so we set it to 0 */
-               vc->vt_mode.frsig = 0;
-               put_pid(vc->vt_pid);
-               vc->vt_pid = get_pid(task_pid(current));
-               /* no switch is required -- saw@shade.msu.ru */
-               vc->vt_newvt = -1;
-               release_console_sem();
-               break;
-       }
-
-       case VT_GETMODE:
-       {
-               struct vt_mode tmp;
-               int rc;
-
-               acquire_console_sem();
-               memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode));
-               release_console_sem();
-
-               rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
-               if (rc)
-                       ret = -EFAULT;
-               break;
-       }
-
-       /*
-        * Returns global vt state. Note that VT 0 is always open, since
-        * it's an alias for the current VT, and people can't use it here.
-        * We cannot return state for more than 16 VTs, since v_state is short.
-        */
-       case VT_GETSTATE:
-       {
-               struct vt_stat __user *vtstat = up;
-               unsigned short state, mask;
-
-               if (put_user(fg_console + 1, &vtstat->v_active))
-                       ret = -EFAULT;
-               else {
-                       state = 1;      /* /dev/tty0 is always open */
-                       for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
-                                                       ++i, mask <<= 1)
-                               if (VT_IS_IN_USE(i))
-                                       state |= mask;
-                       ret = put_user(state, &vtstat->v_state);
-               }
-               break;
-       }
-
-       /*
-        * Returns the first available (non-opened) console.
-        */
-       case VT_OPENQRY:
-               for (i = 0; i < MAX_NR_CONSOLES; ++i)
-                       if (! VT_IS_IN_USE(i))
-                               break;
-               uival = i < MAX_NR_CONSOLES ? (i+1) : -1;
-               goto setint;             
-
-       /*
-        * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
-        * with num >= 1 (switches to vt 0, our console, are not allowed, just
-        * to preserve sanity).
-        */
-       case VT_ACTIVATE:
-               if (!perm)
-                       goto eperm;
-               if (arg == 0 || arg > MAX_NR_CONSOLES)
-                       ret =  -ENXIO;
-               else {
-                       arg--;
-                       acquire_console_sem();
-                       ret = vc_allocate(arg);
-                       release_console_sem();
-                       if (ret)
-                               break;
-                       set_console(arg);
-               }
-               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))) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               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
-        */
-       case VT_WAITACTIVE:
-               if (!perm)
-                       goto eperm;
-               if (arg == 0 || arg > MAX_NR_CONSOLES)
-                       ret = -ENXIO;
-               else
-                       ret = vt_waitactive(arg);
-               break;
-
-       /*
-        * If a vt is under process control, the kernel will not switch to it
-        * immediately, but postpone the operation until the process calls this
-        * ioctl, allowing the switch to complete.
-        *
-        * According to the X sources this is the behavior:
-        *      0:      pending switch-from not OK
-        *      1:      pending switch-from OK
-        *      2:      completed switch-to OK
-        */
-       case VT_RELDISP:
-               if (!perm)
-                       goto eperm;
-
-               if (vc->vt_mode.mode != VT_PROCESS) {
-                       ret = -EINVAL;
-                       break;
-               }
-               /*
-                * Switching-from response
-                */
-               acquire_console_sem();
-               if (vc->vt_newvt >= 0) {
-                       if (arg == 0)
-                               /*
-                                * Switch disallowed, so forget we were trying
-                                * to do it.
-                                */
-                               vc->vt_newvt = -1;
-
-                       else {
-                               /*
-                                * The current vt has been released, so
-                                * complete the switch.
-                                */
-                               int newvt;
-                               newvt = vc->vt_newvt;
-                               vc->vt_newvt = -1;
-                               ret = vc_allocate(newvt);
-                               if (ret) {
-                                       release_console_sem();
-                                       break;
-                               }
-                               /*
-                                * When we actually do the console switch,
-                                * make sure we are atomic with respect to
-                                * other console switches..
-                                */
-                               complete_change_console(vc_cons[newvt].d);
-                       }
-               } else {
-                       /*
-                        * Switched-to response
-                        */
-                       /*
-                        * If it's just an ACK, ignore it
-                        */
-                       if (arg != VT_ACKACQ)
-                               ret = -EINVAL;
-               }
-               release_console_sem();
-               break;
-
-        /*
-         * Disallocate memory associated to VT (but leave VT1)
-         */
-        case VT_DISALLOCATE:
-               if (arg > MAX_NR_CONSOLES) {
-                       ret = -ENXIO;
-                       break;
-               }
-               if (arg == 0) {
-                   /* deallocate all unused consoles, but leave 0 */
-                       acquire_console_sem();
-                       for (i=1; i<MAX_NR_CONSOLES; i++)
-                               if (! VT_BUSY(i))
-                                       vc_deallocate(i);
-                       release_console_sem();
-               } else {
-                       /* deallocate a single console, if possible */
-                       arg--;
-                       if (VT_BUSY(arg))
-                               ret = -EBUSY;
-                       else if (arg) {                       /* leave 0 */
-                               acquire_console_sem();
-                               vc_deallocate(arg);
-                               release_console_sem();
-                       }
-               }
-               break;
-
-       case VT_RESIZE:
-       {
-               struct vt_sizes __user *vtsizes = up;
-               struct vc_data *vc;
-
-               ushort ll,cc;
-               if (!perm)
-                       goto eperm;
-               if (get_user(ll, &vtsizes->v_rows) ||
-                   get_user(cc, &vtsizes->v_cols))
-                       ret = -EFAULT;
-               else {
-                       acquire_console_sem();
-                       for (i = 0; i < MAX_NR_CONSOLES; i++) {
-                               vc = vc_cons[i].d;
-
-                               if (vc) {
-                                       vc->vc_resize_user = 1;
-                                       vc_resize(vc_cons[i].d, cc, ll);
-                               }
-                       }
-                       release_console_sem();
-               }
-               break;
-       }
-
-       case VT_RESIZEX:
-       {
-               struct vt_consize __user *vtconsize = up;
-               ushort ll,cc,vlin,clin,vcol,ccol;
-               if (!perm)
-                       goto eperm;
-               if (!access_ok(VERIFY_READ, vtconsize,
-                               sizeof(struct vt_consize))) {
-                       ret = -EFAULT;
-                       break;
-               }
-               /* FIXME: Should check the copies properly */
-               __get_user(ll, &vtconsize->v_rows);
-               __get_user(cc, &vtconsize->v_cols);
-               __get_user(vlin, &vtconsize->v_vlin);
-               __get_user(clin, &vtconsize->v_clin);
-               __get_user(vcol, &vtconsize->v_vcol);
-               __get_user(ccol, &vtconsize->v_ccol);
-               vlin = vlin ? vlin : vc->vc_scan_lines;
-               if (clin) {
-                       if (ll) {
-                               if (ll != vlin/clin) {
-                                       /* Parameters don't add up */
-                                       ret = -EINVAL;
-                                       break;
-                               }
-                       } else 
-                               ll = vlin/clin;
-               }
-               if (vcol && ccol) {
-                       if (cc) {
-                               if (cc != vcol/ccol) {
-                                       ret = -EINVAL;
-                                       break;
-                               }
-                       } else
-                               cc = vcol/ccol;
-               }
-
-               if (clin > 32) {
-                       ret =  -EINVAL;
-                       break;
-               }
-                   
-               for (i = 0; i < MAX_NR_CONSOLES; i++) {
-                       if (!vc_cons[i].d)
-                               continue;
-                       acquire_console_sem();
-                       if (vlin)
-                               vc_cons[i].d->vc_scan_lines = vlin;
-                       if (clin)
-                               vc_cons[i].d->vc_font.height = clin;
-                       vc_cons[i].d->vc_resize_user = 1;
-                       vc_resize(vc_cons[i].d, cc, ll);
-                       release_console_sem();
-               }
-               break;
-       }
-
-       case PIO_FONT: {
-               if (!perm)
-                       goto eperm;
-               op.op = KD_FONT_OP_SET;
-               op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
-               op.width = 8;
-               op.height = 0;
-               op.charcount = 256;
-               op.data = up;
-               ret = con_font_op(vc_cons[fg_console].d, &op);
-               break;
-       }
-
-       case GIO_FONT: {
-               op.op = KD_FONT_OP_GET;
-               op.flags = KD_FONT_FLAG_OLD;
-               op.width = 8;
-               op.height = 32;
-               op.charcount = 256;
-               op.data = up;
-               ret = con_font_op(vc_cons[fg_console].d, &op);
-               break;
-       }
-
-       case PIO_CMAP:
-                if (!perm)
-                       ret = -EPERM;
-               else
-                       ret = con_set_cmap(up);
-               break;
-
-       case GIO_CMAP:
-                ret = con_get_cmap(up);
-               break;
-
-       case PIO_FONTX:
-       case GIO_FONTX:
-               ret = do_fontx_ioctl(cmd, up, perm, &op);
-               break;
-
-       case PIO_FONTRESET:
-       {
-               if (!perm)
-                       goto eperm;
-
-#ifdef BROKEN_GRAPHICS_PROGRAMS
-               /* With BROKEN_GRAPHICS_PROGRAMS defined, the default
-                  font is not saved. */
-               ret = -ENOSYS;
-               break;
-#else
-               {
-               op.op = KD_FONT_OP_SET_DEFAULT;
-               op.data = NULL;
-               ret = con_font_op(vc_cons[fg_console].d, &op);
-               if (ret)
-                       break;
-               con_set_default_unimap(vc_cons[fg_console].d);
-               break;
-               }
-#endif
-       }
-
-       case KDFONTOP: {
-               if (copy_from_user(&op, up, sizeof(op))) {
-                       ret = -EFAULT;
-                       break;
-               }
-               if (!perm && op.op != KD_FONT_OP_GET)
-                       goto eperm;
-               ret = con_font_op(vc, &op);
-               if (ret)
-                       break;
-               if (copy_to_user(up, &op, sizeof(op)))
-                       ret = -EFAULT;
-               break;
-       }
-
-       case PIO_SCRNMAP:
-               if (!perm)
-                       ret = -EPERM;
-               else
-                       ret = con_set_trans_old(up);
-               break;
-
-       case GIO_SCRNMAP:
-               ret = con_get_trans_old(up);
-               break;
-
-       case PIO_UNISCRNMAP:
-               if (!perm)
-                       ret = -EPERM;
-               else
-                       ret = con_set_trans_new(up);
-               break;
-
-       case GIO_UNISCRNMAP:
-               ret = con_get_trans_new(up);
-               break;
-
-       case PIO_UNIMAPCLR:
-             { struct unimapinit ui;
-               if (!perm)
-                       goto eperm;
-               ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
-               if (ret)
-                       ret = -EFAULT;
-               else
-                       con_clear_unimap(vc, &ui);
-               break;
-             }
-
-       case PIO_UNIMAP:
-       case GIO_UNIMAP:
-               ret = do_unimap_ioctl(cmd, up, perm, vc);
-               break;
-
-       case VT_LOCKSWITCH:
-               if (!capable(CAP_SYS_TTY_CONFIG))
-                       goto eperm;
-               vt_dont_switch = 1;
-               break;
-       case VT_UNLOCKSWITCH:
-               if (!capable(CAP_SYS_TTY_CONFIG))
-                       goto eperm;
-               vt_dont_switch = 0;
-               break;
-       case VT_GETHIFONTMASK:
-               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;
-       }
-out:
-       tty_unlock();
-       return ret;
-eperm:
-       ret = -EPERM;
-       goto out;
-}
-
-void reset_vc(struct vc_data *vc)
-{
-       vc->vc_mode = KD_TEXT;
-       kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
-       vc->vt_mode.mode = VT_AUTO;
-       vc->vt_mode.waitv = 0;
-       vc->vt_mode.relsig = 0;
-       vc->vt_mode.acqsig = 0;
-       vc->vt_mode.frsig = 0;
-       put_pid(vc->vt_pid);
-       vc->vt_pid = NULL;
-       vc->vt_newvt = -1;
-       if (!in_interrupt())    /* Via keyboard.c:SAK() - akpm */
-               reset_palette(vc);
-}
-
-void vc_SAK(struct work_struct *work)
-{
-       struct vc *vc_con =
-               container_of(work, struct vc, SAK_work);
-       struct vc_data *vc;
-       struct tty_struct *tty;
-
-       acquire_console_sem();
-       vc = vc_con->d;
-       if (vc) {
-               tty = vc->port.tty;
-               /*
-                * SAK should also work in all raw modes and reset
-                * them properly.
-                */
-               if (tty)
-                       __do_SAK(tty);
-               reset_vc(vc);
-       }
-       release_console_sem();
-}
-
-#ifdef CONFIG_COMPAT
-
-struct compat_consolefontdesc {
-       unsigned short charcount;       /* characters in font (256 or 512) */
-       unsigned short charheight;      /* scan lines per character (1-32) */
-       compat_caddr_t chardata;        /* font data in expanded form */
-};
-
-static inline int
-compat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd,
-                        int perm, struct console_font_op *op)
-{
-       struct compat_consolefontdesc cfdarg;
-       int i;
-
-       if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc)))
-               return -EFAULT;
-
-       switch (cmd) {
-       case PIO_FONTX:
-               if (!perm)
-                       return -EPERM;
-               op->op = KD_FONT_OP_SET;
-               op->flags = KD_FONT_FLAG_OLD;
-               op->width = 8;
-               op->height = cfdarg.charheight;
-               op->charcount = cfdarg.charcount;
-               op->data = compat_ptr(cfdarg.chardata);
-               return con_font_op(vc_cons[fg_console].d, op);
-       case GIO_FONTX:
-               op->op = KD_FONT_OP_GET;
-               op->flags = KD_FONT_FLAG_OLD;
-               op->width = 8;
-               op->height = cfdarg.charheight;
-               op->charcount = cfdarg.charcount;
-               op->data = compat_ptr(cfdarg.chardata);
-               i = con_font_op(vc_cons[fg_console].d, op);
-               if (i)
-                       return i;
-               cfdarg.charheight = op->height;
-               cfdarg.charcount = op->charcount;
-               if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc)))
-                       return -EFAULT;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-struct compat_console_font_op {
-       compat_uint_t op;        /* operation code KD_FONT_OP_* */
-       compat_uint_t flags;     /* KD_FONT_FLAG_* */
-       compat_uint_t width, height;     /* font size */
-       compat_uint_t charcount;
-       compat_caddr_t data;    /* font data with height fixed to 32 */
-};
-
-static inline int
-compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop,
-                        int perm, struct console_font_op *op, struct vc_data *vc)
-{
-       int i;
-
-       if (copy_from_user(op, fontop, sizeof(struct compat_console_font_op)))
-               return -EFAULT;
-       if (!perm && op->op != KD_FONT_OP_GET)
-               return -EPERM;
-       op->data = compat_ptr(((struct compat_console_font_op *)op)->data);
-       op->flags |= KD_FONT_FLAG_OLD;
-       i = con_font_op(vc, op);
-       if (i)
-               return i;
-       ((struct compat_console_font_op *)op)->data = (unsigned long)op->data;
-       if (copy_to_user(fontop, op, sizeof(struct compat_console_font_op)))
-               return -EFAULT;
-       return 0;
-}
-
-struct compat_unimapdesc {
-       unsigned short entry_ct;
-       compat_caddr_t entries;
-};
-
-static inline int
-compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
-                        int perm, struct vc_data *vc)
-{
-       struct compat_unimapdesc tmp;
-       struct unipair __user *tmp_entries;
-
-       if (copy_from_user(&tmp, user_ud, sizeof tmp))
-               return -EFAULT;
-       tmp_entries = compat_ptr(tmp.entries);
-       if (tmp_entries)
-               if (!access_ok(VERIFY_WRITE, tmp_entries,
-                               tmp.entry_ct*sizeof(struct unipair)))
-                       return -EFAULT;
-       switch (cmd) {
-       case PIO_UNIMAP:
-               if (!perm)
-                       return -EPERM;
-               return con_set_unimap(vc, tmp.entry_ct, tmp_entries);
-       case GIO_UNIMAP:
-               if (!perm && fg_console != vc->vc_num)
-                       return -EPERM;
-               return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp_entries);
-       }
-       return 0;
-}
-
-long vt_compat_ioctl(struct tty_struct *tty, struct file * file,
-            unsigned int cmd, unsigned long arg)
-{
-       struct vc_data *vc = tty->driver_data;
-       struct console_font_op op;      /* used in multiple places here */
-       struct kbd_struct *kbd;
-       unsigned int console;
-       void __user *up = (void __user *)arg;
-       int perm;
-       int ret = 0;
-
-       console = vc->vc_num;
-
-       tty_lock();
-
-       if (!vc_cons_allocated(console)) {      /* impossible? */
-               ret = -ENOIOCTLCMD;
-               goto out;
-       }
-
-       /*
-        * To have permissions to do most of the vt ioctls, we either have
-        * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
-        */
-       perm = 0;
-       if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
-               perm = 1;
-
-       kbd = kbd_table + console;
-       switch (cmd) {
-       /*
-        * these need special handlers for incompatible data structures
-        */
-       case PIO_FONTX:
-       case GIO_FONTX:
-               ret = compat_fontx_ioctl(cmd, up, perm, &op);
-               break;
-
-       case KDFONTOP:
-               ret = compat_kdfontop_ioctl(up, perm, &op, vc);
-               break;
-
-       case PIO_UNIMAP:
-       case GIO_UNIMAP:
-               ret = compat_unimap_ioctl(cmd, up, perm, vc);
-               break;
-
-       /*
-        * all these treat 'arg' as an integer
-        */
-       case KIOCSOUND:
-       case KDMKTONE:
-#ifdef CONFIG_X86
-       case KDADDIO:
-       case KDDELIO:
-#endif
-       case KDSETMODE:
-       case KDMAPDISP:
-       case KDUNMAPDISP:
-       case KDSKBMODE:
-       case KDSKBMETA:
-       case KDSKBLED:
-       case KDSETLED:
-       case KDSIGACCEPT:
-       case VT_ACTIVATE:
-       case VT_WAITACTIVE:
-       case VT_RELDISP:
-       case VT_DISALLOCATE:
-       case VT_RESIZE:
-       case VT_RESIZEX:
-               goto fallback;
-
-       /*
-        * the rest has a compatible data structure behind arg,
-        * but we have to convert it to a proper 64 bit pointer.
-        */
-       default:
-               arg = (unsigned long)compat_ptr(arg);
-               goto fallback;
-       }
-out:
-       tty_unlock();
-       return ret;
-
-fallback:
-       tty_unlock();
-       return vt_ioctl(tty, file, cmd, arg);
-}
-
-
-#endif /* CONFIG_COMPAT */
-
-
-/*
- * 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;
-
-       /*
-        * If we're switching, we could be going from KD_GRAPHICS to
-        * KD_TEXT mode or vice versa, which means we need to blank or
-        * unblank the screen later.
-        */
-       old_vc_mode = vc_cons[fg_console].d->vc_mode;
-       switch_screen(vc);
-
-       /*
-        * This can't appear below a successful kill_pid().  If it did,
-        * then the *blank_screen operation could occur while X, having
-        * received acqsig, is waking up on another processor.  This
-        * condition can lead to overlapping accesses to the VGA range
-        * and the framebuffer (causing system lockups).
-        *
-        * To account for this we duplicate this code below only if the
-        * controlling process is gone and we've called reset_vc.
-        */
-       if (old_vc_mode != vc->vc_mode) {
-               if (vc->vc_mode == KD_TEXT)
-                       do_unblank_screen(1);
-               else
-                       do_blank_screen(1);
-       }
-
-       /*
-        * If this new console is under process control, send it a signal
-        * telling it that it has acquired. Also check if it has died and
-        * clean up (similar to logic employed in change_console())
-        */
-       if (vc->vt_mode.mode == VT_PROCESS) {
-               /*
-                * Send the signal as privileged - kill_pid() will
-                * tell us if the process has gone or something else
-                * is awry
-                */
-               if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) {
-               /*
-                * The controlling process has died, so we revert back to
-                * normal operation. In this case, we'll also change back
-                * to KD_TEXT mode. I'm not sure if this is strictly correct
-                * but it saves the agony when the X server dies and the screen
-                * remains blanked due to KD_GRAPHICS! It would be nice to do
-                * this outside of VT_PROCESS but there is no single process
-                * to account for and tracking tty count may be undesirable.
-                */
-                       reset_vc(vc);
-
-                       if (old_vc_mode != vc->vc_mode) {
-                               if (vc->vc_mode == KD_TEXT)
-                                       do_unblank_screen(1);
-                               else
-                                       do_blank_screen(1);
-                       }
-               }
-       }
-
-       /*
-        * Wake anyone waiting for their VT to activate
-        */
-       vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num);
-       return;
-}
-
-/*
- * Performs the front-end of a vt switch
- */
-void change_console(struct vc_data *new_vc)
-{
-       struct vc_data *vc;
-
-       if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch)
-               return;
-
-       /*
-        * If this vt is in process mode, then we need to handshake with
-        * that process before switching. Essentially, we store where that
-        * vt wants to switch to and wait for it to tell us when it's done
-        * (via VT_RELDISP ioctl).
-        *
-        * We also check to see if the controlling process still exists.
-        * If it doesn't, we reset this vt to auto mode and continue.
-        * This is a cheap way to track process control. The worst thing
-        * that can happen is: we send a signal to a process, it dies, and
-        * the switch gets "lost" waiting for a response; hopefully, the
-        * user will try again, we'll detect the process is gone (unless
-        * the user waits just the right amount of time :-) and revert the
-        * vt to auto control.
-        */
-       vc = vc_cons[fg_console].d;
-       if (vc->vt_mode.mode == VT_PROCESS) {
-               /*
-                * Send the signal as privileged - kill_pid() will
-                * tell us if the process has gone or something else
-                * is awry.
-                *
-                * We need to set vt_newvt *before* sending the signal or we
-                * have a race.
-                */
-               vc->vt_newvt = new_vc->vc_num;
-               if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
-                       /*
-                        * It worked. Mark the vt to switch to and
-                        * return. The process needs to send us a
-                        * VT_RELDISP ioctl to complete the switch.
-                        */
-                       return;
-               }
-
-               /*
-                * The controlling process has died, so we revert back to
-                * normal operation. In this case, we'll also change back
-                * to KD_TEXT mode. I'm not sure if this is strictly correct
-                * but it saves the agony when the X server dies and the screen
-                * remains blanked due to KD_GRAPHICS! It would be nice to do
-                * this outside of VT_PROCESS but there is no single process
-                * to account for and tracking tty count may be undesirable.
-                */
-               reset_vc(vc);
-
-               /*
-                * Fall through to normal (VT_AUTO) handling of the switch...
-                */
-       }
-
-       /*
-        * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
-        */
-       if (vc->vc_mode == KD_GRAPHICS)
-               return;
-
-       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();
-       tty_lock();
-       if (vt_waitactive(vt + 1)) {
-               pr_debug("Suspend: Can't switch VCs.");
-               tty_unlock();
-               return -EINTR;
-       }
-       tty_unlock();
-       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);
index 9dcb17d51aee737bcbb4ac478807c04311588d6c..84eb607d6c031b4275e834604d4c0c0729fa8502 100644 (file)
@@ -577,17 +577,11 @@ static int ohci_update_phy_reg(struct fw_card *card, int addr,
        return ret;
 }
 
-static int ar_context_add_page(struct ar_context *ctx)
+static void ar_context_link_page(struct ar_context *ctx,
+                                struct ar_buffer *ab, dma_addr_t ab_bus)
 {
-       struct device *dev = ctx->ohci->card.device;
-       struct ar_buffer *ab;
-       dma_addr_t uninitialized_var(ab_bus);
        size_t offset;
 
-       ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC);
-       if (ab == NULL)
-               return -ENOMEM;
-
        ab->next = NULL;
        memset(&ab->descriptor, 0, sizeof(ab->descriptor));
        ab->descriptor.control        = cpu_to_le16(DESCRIPTOR_INPUT_MORE |
@@ -606,6 +600,19 @@ static int ar_context_add_page(struct ar_context *ctx)
 
        reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
        flush_writes(ctx->ohci);
+}
+
+static int ar_context_add_page(struct ar_context *ctx)
+{
+       struct device *dev = ctx->ohci->card.device;
+       struct ar_buffer *ab;
+       dma_addr_t uninitialized_var(ab_bus);
+
+       ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC);
+       if (ab == NULL)
+               return -ENOMEM;
+
+       ar_context_link_page(ctx, ab, ab_bus);
 
        return 0;
 }
@@ -730,16 +737,17 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
 static void ar_context_tasklet(unsigned long data)
 {
        struct ar_context *ctx = (struct ar_context *)data;
-       struct fw_ohci *ohci = ctx->ohci;
        struct ar_buffer *ab;
        struct descriptor *d;
        void *buffer, *end;
+       __le16 res_count;
 
        ab = ctx->current_buffer;
        d = &ab->descriptor;
 
-       if (d->res_count == 0) {
-               size_t size, rest, offset;
+       res_count = ACCESS_ONCE(d->res_count);
+       if (res_count == 0) {
+               size_t size, size2, rest, pktsize, size3, offset;
                dma_addr_t start_bus;
                void *start;
 
@@ -750,29 +758,63 @@ static void ar_context_tasklet(unsigned long data)
                 */
 
                offset = offsetof(struct ar_buffer, data);
-               start = buffer = ab;
+               start = ab;
                start_bus = le32_to_cpu(ab->descriptor.data_address) - offset;
+               buffer = ab->data;
 
                ab = ab->next;
                d = &ab->descriptor;
-               size = buffer + PAGE_SIZE - ctx->pointer;
+               size = start + PAGE_SIZE - ctx->pointer;
+               /* valid buffer data in the next page */
                rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count);
+               /* what actually fits in this page */
+               size2 = min(rest, (size_t)PAGE_SIZE - offset - size);
                memmove(buffer, ctx->pointer, size);
-               memcpy(buffer + size, ab->data, rest);
-               ctx->current_buffer = ab;
-               ctx->pointer = (void *) ab->data + rest;
-               end = buffer + size + rest;
+               memcpy(buffer + size, ab->data, size2);
+
+               while (size > 0) {
+                       void *next = handle_ar_packet(ctx, buffer);
+                       pktsize = next - buffer;
+                       if (pktsize >= size) {
+                               /*
+                                * We have handled all the data that was
+                                * originally in this page, so we can now
+                                * continue in the next page.
+                                */
+                               buffer = next;
+                               break;
+                       }
+                       /* move the next packet to the start of the buffer */
+                       memmove(buffer, next, size + size2 - pktsize);
+                       size -= pktsize;
+                       /* fill up this page again */
+                       size3 = min(rest - size2,
+                                   (size_t)PAGE_SIZE - offset - size - size2);
+                       memcpy(buffer + size + size2,
+                              (void *) ab->data + size2, size3);
+                       size2 += size3;
+               }
 
-               while (buffer < end)
-                       buffer = handle_ar_packet(ctx, buffer);
+               if (rest > 0) {
+                       /* handle the packets that are fully in the next page */
+                       buffer = (void *) ab->data +
+                                       (buffer - (start + offset + size));
+                       end = (void *) ab->data + rest;
+
+                       while (buffer < end)
+                               buffer = handle_ar_packet(ctx, buffer);
 
-               dma_free_coherent(ohci->card.device, PAGE_SIZE,
-                                 start, start_bus);
-               ar_context_add_page(ctx);
+                       ctx->current_buffer = ab;
+                       ctx->pointer = end;
+
+                       ar_context_link_page(ctx, start, start_bus);
+               } else {
+                       ctx->pointer = start + PAGE_SIZE;
+               }
        } else {
                buffer = ctx->pointer;
                ctx->pointer = end =
-                       (void *) ab + PAGE_SIZE - le16_to_cpu(d->res_count);
+                       (void *) ab + PAGE_SIZE - le16_to_cpu(res_count);
 
                while (buffer < end)
                        buffer = handle_ar_packet(ctx, buffer);
index 267626178678363882ad14d01e96122ccfbfe2d2..4b50601027d3f4787249651c8d58da5126603f12 100644 (file)
@@ -82,7 +82,7 @@ static struct ltc4261_data *ltc4261_update_device(struct device *dev)
                        val = i2c_smbus_read_byte_data(client, i);
                        if (unlikely(val < 0)) {
                                dev_dbg(dev,
-                                       "Failed to read ADC value: error %d",
+                                       "Failed to read ADC value: error %d\n",
                                        val);
                                ret = ERR_PTR(val);
                                goto abort;
@@ -230,8 +230,7 @@ static int ltc4261_probe(struct i2c_client *client,
                return -ENODEV;
 
        if (i2c_smbus_read_byte_data(client, LTC4261_STATUS) < 0) {
-               dev_err(&client->dev, "Failed to read register %d:%02x:%02x\n",
-                       adapter->id, client->addr, LTC4261_STATUS);
+               dev_err(&client->dev, "Failed to read status register\n");
                return -ENODEV;
        }
 
index c950be3cce21defb04ec4a75c0f0a05a71e846f8..3a6321cb8030e617aabda9f122fcea901d083f2b 100644 (file)
@@ -99,6 +99,7 @@ config I2C_I801
            ICH10
            5/3400 Series (PCH)
            Cougar Point (PCH)
+           Patsburg (PCH)
 
          This driver can also be built as a module.  If so, the module
          will be called i2c-i801.
index 59d65981eed7edae2704c75fc85672ad08a2983b..02835ce7ff4b1a8969e44b7549b6f93b36b5b3e2 100644 (file)
@@ -3,6 +3,8 @@
     Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
     <mdsxyz123@yahoo.com>
     Copyright (C) 2007, 2008   Jean Delvare <khali@linux-fr.org>
+    Copyright (C) 2010         Intel Corporation,
+                               David Woodhouse <dwmw2@infradead.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
   ICH10                 0x3a60     32     hard     yes     yes     yes
   5/3400 Series (PCH)   0x3b30     32     hard     yes     yes     yes
   Cougar Point (PCH)    0x1c22     32     hard     yes     yes     yes
+  Patsburg (PCH)        0x1d22     32     hard     yes     yes     yes
+  Patsburg (PCH) IDF    0x1d70     32     hard     yes     yes     yes
+  Patsburg (PCH) IDF    0x1d71     32     hard     yes     yes     yes
+  Patsburg (PCH) IDF    0x1d72     32     hard     yes     yes     yes
 
   Features supported by this driver:
   Software PEC                     no
   Block buffer                     yes
   Block process call transaction   no
   I2C block read transaction       yes  (doesn't use the block buffer)
+  Slave mode                       no
 
   See the file Documentation/i2c/busses/i2c-i801 for details.
 */
 
-/* Note: we assume there can only be one I801, with one SMBus interface */
-
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/dmi.h>
 
 /* I801 SMBus address offsets */
-#define SMBHSTSTS      (0 + i801_smba)
-#define SMBHSTCNT      (2 + i801_smba)
-#define SMBHSTCMD      (3 + i801_smba)
-#define SMBHSTADD      (4 + i801_smba)
-#define SMBHSTDAT0     (5 + i801_smba)
-#define SMBHSTDAT1     (6 + i801_smba)
-#define SMBBLKDAT      (7 + i801_smba)
-#define SMBPEC         (8 + i801_smba)         /* ICH3 and later */
-#define SMBAUXSTS      (12 + i801_smba)        /* ICH4 and later */
-#define SMBAUXCTL      (13 + i801_smba)        /* ICH4 and later */
+#define SMBHSTSTS(p)   (0 + (p)->smba)
+#define SMBHSTCNT(p)   (2 + (p)->smba)
+#define SMBHSTCMD(p)   (3 + (p)->smba)
+#define SMBHSTADD(p)   (4 + (p)->smba)
+#define SMBHSTDAT0(p)  (5 + (p)->smba)
+#define SMBHSTDAT1(p)  (6 + (p)->smba)
+#define SMBBLKDAT(p)   (7 + (p)->smba)
+#define SMBPEC(p)      (8 + (p)->smba)         /* ICH3 and later */
+#define SMBAUXSTS(p)   (12 + (p)->smba)        /* ICH4 and later */
+#define SMBAUXCTL(p)   (13 + (p)->smba)        /* ICH4 and later */
 
 /* PCI Address Constants */
 #define SMBBAR         4
                                 SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \
                                 SMBHSTSTS_INTR)
 
-static unsigned long i801_smba;
-static unsigned char i801_original_hstcfg;
+/* Patsburg also has three 'Integrated Device Function' SMBus controllers */
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0        0x1d70
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1        0x1d71
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2        0x1d72
+
+struct i801_priv {
+       struct i2c_adapter adapter;
+       unsigned long smba;
+       unsigned char original_hstcfg;
+       struct pci_dev *pci_dev;
+       unsigned int features;
+};
+
 static struct pci_driver i801_driver;
-static struct pci_dev *I801_dev;
 
 #define FEATURE_SMBUS_PEC      (1 << 0)
 #define FEATURE_BLOCK_BUFFER   (1 << 1)
 #define FEATURE_BLOCK_PROC     (1 << 2)
 #define FEATURE_I2C_BLOCK_READ (1 << 3)
-static unsigned int i801_features;
 
 static const char *i801_feature_names[] = {
        "SMBus PEC",
@@ -151,24 +165,24 @@ MODULE_PARM_DESC(disable_features, "Disable selected driver features");
 
 /* Make sure the SMBus host is ready to start transmitting.
    Return 0 if it is, -EBUSY if it is not. */
-static int i801_check_pre(void)
+static int i801_check_pre(struct i801_priv *priv)
 {
        int status;
 
-       status = inb_p(SMBHSTSTS);
+       status = inb_p(SMBHSTSTS(priv));
        if (status & SMBHSTSTS_HOST_BUSY) {
-               dev_err(&I801_dev->dev, "SMBus is busy, can't use it!\n");
+               dev_err(&priv->pci_dev->dev, "SMBus is busy, can't use it!\n");
                return -EBUSY;
        }
 
        status &= STATUS_FLAGS;
        if (status) {
-               dev_dbg(&I801_dev->dev, "Clearing status flags (%02x)\n",
+               dev_dbg(&priv->pci_dev->dev, "Clearing status flags (%02x)\n",
                        status);
-               outb_p(status, SMBHSTSTS);
-               status = inb_p(SMBHSTSTS) & STATUS_FLAGS;
+               outb_p(status, SMBHSTSTS(priv));
+               status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
                if (status) {
-                       dev_err(&I801_dev->dev,
+                       dev_err(&priv->pci_dev->dev,
                                "Failed clearing status flags (%02x)\n",
                                status);
                        return -EBUSY;
@@ -179,48 +193,50 @@ static int i801_check_pre(void)
 }
 
 /* Convert the status register to an error code, and clear it. */
-static int i801_check_post(int status, int timeout)
+static int i801_check_post(struct i801_priv *priv, int status, int timeout)
 {
        int result = 0;
 
        /* If the SMBus is still busy, we give up */
        if (timeout) {
-               dev_err(&I801_dev->dev, "Transaction timeout\n");
+               dev_err(&priv->pci_dev->dev, "Transaction timeout\n");
                /* try to stop the current command */
-               dev_dbg(&I801_dev->dev, "Terminating the current operation\n");
-               outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT);
+               dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n");
+               outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL,
+                      SMBHSTCNT(priv));
                msleep(1);
-               outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT);
+               outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL),
+                      SMBHSTCNT(priv));
 
                /* Check if it worked */
-               status = inb_p(SMBHSTSTS);
+               status = inb_p(SMBHSTSTS(priv));
                if ((status & SMBHSTSTS_HOST_BUSY) ||
                    !(status & SMBHSTSTS_FAILED))
-                       dev_err(&I801_dev->dev,
+                       dev_err(&priv->pci_dev->dev,
                                "Failed terminating the transaction\n");
-               outb_p(STATUS_FLAGS, SMBHSTSTS);
+               outb_p(STATUS_FLAGS, SMBHSTSTS(priv));
                return -ETIMEDOUT;
        }
 
        if (status & SMBHSTSTS_FAILED) {
                result = -EIO;
-               dev_err(&I801_dev->dev, "Transaction failed\n");
+               dev_err(&priv->pci_dev->dev, "Transaction failed\n");
        }
        if (status & SMBHSTSTS_DEV_ERR) {
                result = -ENXIO;
-               dev_dbg(&I801_dev->dev, "No response\n");
+               dev_dbg(&priv->pci_dev->dev, "No response\n");
        }
        if (status & SMBHSTSTS_BUS_ERR) {
                result = -EAGAIN;
-               dev_dbg(&I801_dev->dev, "Lost arbitration\n");
+               dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n");
        }
 
        if (result) {
                /* Clear error flags */
-               outb_p(status & STATUS_FLAGS, SMBHSTSTS);
-               status = inb_p(SMBHSTSTS) & STATUS_FLAGS;
+               outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv));
+               status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
                if (status) {
-                       dev_warn(&I801_dev->dev, "Failed clearing status "
+                       dev_warn(&priv->pci_dev->dev, "Failed clearing status "
                                 "flags at end of transaction (%02x)\n",
                                 status);
                }
@@ -229,86 +245,88 @@ static int i801_check_post(int status, int timeout)
        return result;
 }
 
-static int i801_transaction(int xact)
+static int i801_transaction(struct i801_priv *priv, int xact)
 {
        int status;
        int result;
        int timeout = 0;
 
-       result = i801_check_pre();
+       result = i801_check_pre(priv);
        if (result < 0)
                return result;
 
        /* the current contents of SMBHSTCNT can be overwritten, since PEC,
         * INTREN, SMBSCMD are passed in xact */
-       outb_p(xact | I801_START, SMBHSTCNT);
+       outb_p(xact | I801_START, SMBHSTCNT(priv));
 
        /* We will always wait for a fraction of a second! */
        do {
                msleep(1);
-               status = inb_p(SMBHSTSTS);
+               status = inb_p(SMBHSTSTS(priv));
        } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT));
 
-       result = i801_check_post(status, timeout > MAX_TIMEOUT);
+       result = i801_check_post(priv, status, timeout > MAX_TIMEOUT);
        if (result < 0)
                return result;
 
-       outb_p(SMBHSTSTS_INTR, SMBHSTSTS);
+       outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
        return 0;
 }
 
 /* wait for INTR bit as advised by Intel */
-static void i801_wait_hwpec(void)
+static void i801_wait_hwpec(struct i801_priv *priv)
 {
        int timeout = 0;
        int status;
 
        do {
                msleep(1);
-               status = inb_p(SMBHSTSTS);
+               status = inb_p(SMBHSTSTS(priv));
        } while ((!(status & SMBHSTSTS_INTR))
                 && (timeout++ < MAX_TIMEOUT));
 
        if (timeout > MAX_TIMEOUT)
-               dev_dbg(&I801_dev->dev, "PEC Timeout!\n");
+               dev_dbg(&priv->pci_dev->dev, "PEC Timeout!\n");
 
-       outb_p(status, SMBHSTSTS);
+       outb_p(status, SMBHSTSTS(priv));
 }
 
-static int i801_block_transaction_by_block(union i2c_smbus_data *data,
+static int i801_block_transaction_by_block(struct i801_priv *priv,
+                                          union i2c_smbus_data *data,
                                           char read_write, int hwpec)
 {
        int i, len;
        int status;
 
-       inb_p(SMBHSTCNT); /* reset the data buffer index */
+       inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
 
        /* Use 32-byte buffer to process this transaction */
        if (read_write == I2C_SMBUS_WRITE) {
                len = data->block[0];
-               outb_p(len, SMBHSTDAT0);
+               outb_p(len, SMBHSTDAT0(priv));
                for (i = 0; i < len; i++)
-                       outb_p(data->block[i+1], SMBBLKDAT);
+                       outb_p(data->block[i+1], SMBBLKDAT(priv));
        }
 
-       status = i801_transaction(I801_BLOCK_DATA | ENABLE_INT9 |
+       status = i801_transaction(priv, I801_BLOCK_DATA | ENABLE_INT9 |
                                  I801_PEC_EN * hwpec);
        if (status)
                return status;
 
        if (read_write == I2C_SMBUS_READ) {
-               len = inb_p(SMBHSTDAT0);
+               len = inb_p(SMBHSTDAT0(priv));
                if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
                        return -EPROTO;
 
                data->block[0] = len;
                for (i = 0; i < len; i++)
-                       data->block[i + 1] = inb_p(SMBBLKDAT);
+                       data->block[i + 1] = inb_p(SMBBLKDAT(priv));
        }
        return 0;
 }
 
-static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
+static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
+                                              union i2c_smbus_data *data,
                                               char read_write, int command,
                                               int hwpec)
 {
@@ -318,15 +336,15 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
        int result;
        int timeout;
 
-       result = i801_check_pre();
+       result = i801_check_pre(priv);
        if (result < 0)
                return result;
 
        len = data->block[0];
 
        if (read_write == I2C_SMBUS_WRITE) {
-               outb_p(len, SMBHSTDAT0);
-               outb_p(data->block[1], SMBBLKDAT);
+               outb_p(len, SMBHSTDAT0(priv));
+               outb_p(data->block[1], SMBBLKDAT(priv));
        }
 
        for (i = 1; i <= len; i++) {
@@ -342,34 +360,37 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
                        else
                                smbcmd = I801_BLOCK_DATA;
                }
-               outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
+               outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv));
 
                if (i == 1)
-                       outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
+                       outb_p(inb(SMBHSTCNT(priv)) | I801_START,
+                              SMBHSTCNT(priv));
 
                /* We will always wait for a fraction of a second! */
                timeout = 0;
                do {
                        msleep(1);
-                       status = inb_p(SMBHSTSTS);
+                       status = inb_p(SMBHSTSTS(priv));
                } while ((!(status & SMBHSTSTS_BYTE_DONE))
                         && (timeout++ < MAX_TIMEOUT));
 
-               result = i801_check_post(status, timeout > MAX_TIMEOUT);
+               result = i801_check_post(priv, status, timeout > MAX_TIMEOUT);
                if (result < 0)
                        return result;
 
                if (i == 1 && read_write == I2C_SMBUS_READ
                 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
-                       len = inb_p(SMBHSTDAT0);
+                       len = inb_p(SMBHSTDAT0(priv));
                        if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
-                               dev_err(&I801_dev->dev,
+                               dev_err(&priv->pci_dev->dev,
                                        "Illegal SMBus block read size %d\n",
                                        len);
                                /* Recover */
-                               while (inb_p(SMBHSTSTS) & SMBHSTSTS_HOST_BUSY)
-                                       outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS);
-                               outb_p(SMBHSTSTS_INTR, SMBHSTSTS);
+                               while (inb_p(SMBHSTSTS(priv)) &
+                                      SMBHSTSTS_HOST_BUSY)
+                                       outb_p(SMBHSTSTS_BYTE_DONE,
+                                              SMBHSTSTS(priv));
+                               outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
                                return -EPROTO;
                        }
                        data->block[0] = len;
@@ -377,27 +398,28 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
 
                /* Retrieve/store value in SMBBLKDAT */
                if (read_write == I2C_SMBUS_READ)
-                       data->block[i] = inb_p(SMBBLKDAT);
+                       data->block[i] = inb_p(SMBBLKDAT(priv));
                if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
-                       outb_p(data->block[i+1], SMBBLKDAT);
+                       outb_p(data->block[i+1], SMBBLKDAT(priv));
 
                /* signals SMBBLKDAT ready */
-               outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS);
+               outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS(priv));
        }
 
        return 0;
 }
 
-static int i801_set_block_buffer_mode(void)
+static int i801_set_block_buffer_mode(struct i801_priv *priv)
 {
-       outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_E32B, SMBAUXCTL);
-       if ((inb_p(SMBAUXCTL) & SMBAUXCTL_E32B) == 0)
+       outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
+       if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0)
                return -EIO;
        return 0;
 }
 
 /* Block transaction function */
-static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
+static int i801_block_transaction(struct i801_priv *priv,
+                                 union i2c_smbus_data *data, char read_write,
                                  int command, int hwpec)
 {
        int result = 0;
@@ -406,11 +428,11 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
        if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
                if (read_write == I2C_SMBUS_WRITE) {
                        /* set I2C_EN bit in configuration register */
-                       pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
-                       pci_write_config_byte(I801_dev, SMBHSTCFG,
+                       pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc);
+                       pci_write_config_byte(priv->pci_dev, SMBHSTCFG,
                                              hostc | SMBHSTCFG_I2C_EN);
-               } else if (!(i801_features & FEATURE_I2C_BLOCK_READ)) {
-                       dev_err(&I801_dev->dev,
+               } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) {
+                       dev_err(&priv->pci_dev->dev,
                                "I2C block read is unsupported!\n");
                        return -EOPNOTSUPP;
                }
@@ -429,22 +451,23 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
        /* Experience has shown that the block buffer can only be used for
           SMBus (not I2C) block transactions, even though the datasheet
           doesn't mention this limitation. */
-       if ((i801_features & FEATURE_BLOCK_BUFFER)
+       if ((priv->features & FEATURE_BLOCK_BUFFER)
         && command != I2C_SMBUS_I2C_BLOCK_DATA
-        && i801_set_block_buffer_mode() == 0)
-               result = i801_block_transaction_by_block(data, read_write,
-                                                        hwpec);
+        && i801_set_block_buffer_mode(priv) == 0)
+               result = i801_block_transaction_by_block(priv, data,
+                                                        read_write, hwpec);
        else
-               result = i801_block_transaction_byte_by_byte(data, read_write,
+               result = i801_block_transaction_byte_by_byte(priv, data,
+                                                            read_write,
                                                             command, hwpec);
 
        if (result == 0 && hwpec)
-               i801_wait_hwpec();
+               i801_wait_hwpec(priv);
 
        if (command == I2C_SMBUS_I2C_BLOCK_DATA
         && read_write == I2C_SMBUS_WRITE) {
                /* restore saved configuration register value */
-               pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
+               pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc);
        }
        return result;
 }
@@ -457,81 +480,85 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
        int hwpec;
        int block = 0;
        int ret, xact = 0;
+       struct i801_priv *priv = i2c_get_adapdata(adap);
 
-       hwpec = (i801_features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
+       hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
                && size != I2C_SMBUS_QUICK
                && size != I2C_SMBUS_I2C_BLOCK_DATA;
 
        switch (size) {
        case I2C_SMBUS_QUICK:
                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-                      SMBHSTADD);
+                      SMBHSTADD(priv));
                xact = I801_QUICK;
                break;
        case I2C_SMBUS_BYTE:
                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-                      SMBHSTADD);
+                      SMBHSTADD(priv));
                if (read_write == I2C_SMBUS_WRITE)
-                       outb_p(command, SMBHSTCMD);
+                       outb_p(command, SMBHSTCMD(priv));
                xact = I801_BYTE;
                break;
        case I2C_SMBUS_BYTE_DATA:
                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-                      SMBHSTADD);
-               outb_p(command, SMBHSTCMD);
+                      SMBHSTADD(priv));
+               outb_p(command, SMBHSTCMD(priv));
                if (read_write == I2C_SMBUS_WRITE)
-                       outb_p(data->byte, SMBHSTDAT0);
+                       outb_p(data->byte, SMBHSTDAT0(priv));
                xact = I801_BYTE_DATA;
                break;
        case I2C_SMBUS_WORD_DATA:
                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-                      SMBHSTADD);
-               outb_p(command, SMBHSTCMD);
+                      SMBHSTADD(priv));
+               outb_p(command, SMBHSTCMD(priv));
                if (read_write == I2C_SMBUS_WRITE) {
-                       outb_p(data->word & 0xff, SMBHSTDAT0);
-                       outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+                       outb_p(data->word & 0xff, SMBHSTDAT0(priv));
+                       outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
                }
                xact = I801_WORD_DATA;
                break;
        case I2C_SMBUS_BLOCK_DATA:
                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-                      SMBHSTADD);
-               outb_p(command, SMBHSTCMD);
+                      SMBHSTADD(priv));
+               outb_p(command, SMBHSTCMD(priv));
                block = 1;
                break;
        case I2C_SMBUS_I2C_BLOCK_DATA:
                /* NB: page 240 of ICH5 datasheet shows that the R/#W
                 * bit should be cleared here, even when reading */
-               outb_p((addr & 0x7f) << 1, SMBHSTADD);
+               outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));
                if (read_write == I2C_SMBUS_READ) {
                        /* NB: page 240 of ICH5 datasheet also shows
                         * that DATA1 is the cmd field when reading */
-                       outb_p(command, SMBHSTDAT1);
+                       outb_p(command, SMBHSTDAT1(priv));
                } else
-                       outb_p(command, SMBHSTCMD);
+                       outb_p(command, SMBHSTCMD(priv));
                block = 1;
                break;
        default:
-               dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size);
+               dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
+                       size);
                return -EOPNOTSUPP;
        }
 
        if (hwpec)      /* enable/disable hardware PEC */
-               outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_CRC, SMBAUXCTL);
+               outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
        else
-               outb_p(inb_p(SMBAUXCTL) & (~SMBAUXCTL_CRC), SMBAUXCTL);
+               outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC),
+                      SMBAUXCTL(priv));
 
        if (block)
-               ret = i801_block_transaction(data, read_write, size, hwpec);
+               ret = i801_block_transaction(priv, data, read_write, size,
+                                            hwpec);
        else
-               ret = i801_transaction(xact | ENABLE_INT9);
+               ret = i801_transaction(priv, xact | ENABLE_INT9);
 
        /* Some BIOSes don't like it when PEC is enabled at reboot or resume
           time, so we forcibly disable it after every transaction. Turn off
           E32B for the same reason. */
        if (hwpec || block)
-               outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
-                      SMBAUXCTL);
+               outb_p(inb_p(SMBAUXCTL(priv)) &
+                      ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
 
        if (block)
                return ret;
@@ -543,10 +570,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
        switch (xact & 0x7f) {
        case I801_BYTE: /* Result put in SMBHSTDAT0 */
        case I801_BYTE_DATA:
-               data->byte = inb_p(SMBHSTDAT0);
+               data->byte = inb_p(SMBHSTDAT0(priv));
                break;
        case I801_WORD_DATA:
-               data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+               data->word = inb_p(SMBHSTDAT0(priv)) +
+                            (inb_p(SMBHSTDAT1(priv)) << 8);
                break;
        }
        return 0;
@@ -555,11 +583,13 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
 
 static u32 i801_func(struct i2c_adapter *adapter)
 {
+       struct i801_priv *priv = i2c_get_adapdata(adapter);
+
        return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
               I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
               I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
-              ((i801_features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
-              ((i801_features & FEATURE_I2C_BLOCK_READ) ?
+              ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
+              ((priv->features & FEATURE_I2C_BLOCK_READ) ?
                I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0);
 }
 
@@ -568,12 +598,6 @@ static const struct i2c_algorithm smbus_algorithm = {
        .functionality  = i801_func,
 };
 
-static struct i2c_adapter i801_adapter = {
-       .owner          = THIS_MODULE,
-       .class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
-       .algo           = &smbus_algorithm,
-};
-
 static const struct pci_device_id i801_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) },
@@ -592,6 +616,10 @@ static const struct pci_device_id i801_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) },
        { 0, }
 };
 
@@ -704,16 +732,25 @@ static int __devinit i801_probe(struct pci_dev *dev,
 {
        unsigned char temp;
        int err, i;
+       struct i801_priv *priv;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       i2c_set_adapdata(&priv->adapter, priv);
+       priv->adapter.owner = THIS_MODULE;
+       priv->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+       priv->adapter.algo = &smbus_algorithm;
 
-       I801_dev = dev;
-       i801_features = 0;
+       priv->pci_dev = dev;
        switch (dev->device) {
        default:
-               i801_features |= FEATURE_I2C_BLOCK_READ;
+               priv->features |= FEATURE_I2C_BLOCK_READ;
                /* fall through */
        case PCI_DEVICE_ID_INTEL_82801DB_3:
-               i801_features |= FEATURE_SMBUS_PEC;
-               i801_features |= FEATURE_BLOCK_BUFFER;
+               priv->features |= FEATURE_SMBUS_PEC;
+               priv->features |= FEATURE_BLOCK_BUFFER;
                /* fall through */
        case PCI_DEVICE_ID_INTEL_82801CA_3:
        case PCI_DEVICE_ID_INTEL_82801BA_2:
@@ -724,11 +761,11 @@ static int __devinit i801_probe(struct pci_dev *dev,
 
        /* Disable features on user request */
        for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) {
-               if (i801_features & disable_features & (1 << i))
+               if (priv->features & disable_features & (1 << i))
                        dev_notice(&dev->dev, "%s disabled by user\n",
                                   i801_feature_names[i]);
        }
-       i801_features &= ~disable_features;
+       priv->features &= ~disable_features;
 
        err = pci_enable_device(dev);
        if (err) {
@@ -738,8 +775,8 @@ static int __devinit i801_probe(struct pci_dev *dev,
        }
 
        /* Determine the address of the SMBus area */
-       i801_smba = pci_resource_start(dev, SMBBAR);
-       if (!i801_smba) {
+       priv->smba = pci_resource_start(dev, SMBBAR);
+       if (!priv->smba) {
                dev_err(&dev->dev, "SMBus base address uninitialized, "
                        "upgrade BIOS\n");
                err = -ENODEV;
@@ -755,19 +792,19 @@ static int __devinit i801_probe(struct pci_dev *dev,
        err = pci_request_region(dev, SMBBAR, i801_driver.name);
        if (err) {
                dev_err(&dev->dev, "Failed to request SMBus region "
-                       "0x%lx-0x%Lx\n", i801_smba,
+                       "0x%lx-0x%Lx\n", priv->smba,
                        (unsigned long long)pci_resource_end(dev, SMBBAR));
                goto exit;
        }
 
-       pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
-       i801_original_hstcfg = temp;
+       pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &temp);
+       priv->original_hstcfg = temp;
        temp &= ~SMBHSTCFG_I2C_EN;      /* SMBus timing */
        if (!(temp & SMBHSTCFG_HST_EN)) {
                dev_info(&dev->dev, "Enabling SMBus device\n");
                temp |= SMBHSTCFG_HST_EN;
        }
-       pci_write_config_byte(I801_dev, SMBHSTCFG, temp);
+       pci_write_config_byte(priv->pci_dev, SMBHSTCFG, temp);
 
        if (temp & SMBHSTCFG_SMB_SMI_EN)
                dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
@@ -775,19 +812,19 @@ static int __devinit i801_probe(struct pci_dev *dev,
                dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
 
        /* Clear special mode bits */
-       if (i801_features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
-               outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
-                      SMBAUXCTL);
+       if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
+               outb_p(inb_p(SMBAUXCTL(priv)) &
+                      ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
 
        /* set up the sysfs linkage to our parent device */
-       i801_adapter.dev.parent = &dev->dev;
+       priv->adapter.dev.parent = &dev->dev;
 
        /* Retry up to 3 times on lost arbitration */
-       i801_adapter.retries = 3;
+       priv->adapter.retries = 3;
 
-       snprintf(i801_adapter.name, sizeof(i801_adapter.name),
-               "SMBus I801 adapter at %04lx", i801_smba);
-       err = i2c_add_adapter(&i801_adapter);
+       snprintf(priv->adapter.name, sizeof(priv->adapter.name),
+               "SMBus I801 adapter at %04lx", priv->smba);
+       err = i2c_add_adapter(&priv->adapter);
        if (err) {
                dev_err(&dev->dev, "Failed to add SMBus adapter\n");
                goto exit_release;
@@ -801,27 +838,33 @@ static int __devinit i801_probe(struct pci_dev *dev,
                memset(&info, 0, sizeof(struct i2c_board_info));
                info.addr = apanel_addr;
                strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
-               i2c_new_device(&i801_adapter, &info);
+               i2c_new_device(&priv->adapter, &info);
        }
 #endif
 #if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
        if (dmi_name_in_vendors("FUJITSU"))
-               dmi_walk(dmi_check_onboard_devices, &i801_adapter);
+               dmi_walk(dmi_check_onboard_devices, &priv->adapter);
 #endif
 
+       pci_set_drvdata(dev, priv);
        return 0;
 
 exit_release:
        pci_release_region(dev, SMBBAR);
 exit:
+       kfree(priv);
        return err;
 }
 
 static void __devexit i801_remove(struct pci_dev *dev)
 {
-       i2c_del_adapter(&i801_adapter);
-       pci_write_config_byte(I801_dev, SMBHSTCFG, i801_original_hstcfg);
+       struct i801_priv *priv = pci_get_drvdata(dev);
+
+       i2c_del_adapter(&priv->adapter);
+       pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
        pci_release_region(dev, SMBBAR);
+       pci_set_drvdata(dev, NULL);
+       kfree(priv);
        /*
         * do not call pci_disable_device(dev) since it can cause hard hangs on
         * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
@@ -831,8 +874,10 @@ static void __devexit i801_remove(struct pci_dev *dev)
 #ifdef CONFIG_PM
 static int i801_suspend(struct pci_dev *dev, pm_message_t mesg)
 {
+       struct i801_priv *priv = pci_get_drvdata(dev);
+
        pci_save_state(dev);
-       pci_write_config_byte(dev, SMBHSTCFG, i801_original_hstcfg);
+       pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
        pci_set_power_state(dev, pci_choose_state(dev, mesg));
        return 0;
 }
index a9cf768316343df7eafeda3f7c4bb58876c3f571..b77f9991278e791557e47638ce078b157cf52993 100644 (file)
@@ -630,7 +630,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)
        /* Just update the base values (i.e. touchpad in untouched state) */
        if (dev->data[dev->info->datalen - 1] & ATP_STATUS_BASE_UPDATE) {
 
-               dprintk(KERN_DEBUG "appletouch: updated base values\n");
+               dprintk("appletouch: updated base values\n");
 
                memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
                goto exit;
index ba6f0bd1e762e494961f6eab23204fb37eff63c0..bc3b5187f3a391504f275567d7143e878dda5c9b 100644 (file)
@@ -129,6 +129,9 @@ struct ad7879 {
        u16                     cmd_crtl1;
        u16                     cmd_crtl2;
        u16                     cmd_crtl3;
+       int                     x;
+       int                     y;
+       int                     Rt;
 };
 
 static int ad7879_read(struct ad7879 *ts, u8 reg)
@@ -175,13 +178,32 @@ static int ad7879_report(struct ad7879 *ts)
                Rt /= z1;
                Rt = (Rt + 2047) >> 12;
 
-               if (!timer_pending(&ts->timer))
+               /*
+                * Sample found inconsistent, pressure is beyond
+                * the maximum. Don't report it to user space.
+                */
+               if (Rt > ts->pressure_max)
+                       return -EINVAL;
+
+               /*
+                * Note that we delay reporting events by one sample.
+                * This is done to avoid reporting last sample of the
+                * touch sequence, which may be incomplete if finger
+                * leaves the surface before last reading is taken.
+                */
+               if (timer_pending(&ts->timer)) {
+                       /* Touch continues */
                        input_report_key(input_dev, BTN_TOUCH, 1);
+                       input_report_abs(input_dev, ABS_X, ts->x);
+                       input_report_abs(input_dev, ABS_Y, ts->y);
+                       input_report_abs(input_dev, ABS_PRESSURE, ts->Rt);
+                       input_sync(input_dev);
+               }
+
+               ts->x = x;
+               ts->y = y;
+               ts->Rt = Rt;
 
-               input_report_abs(input_dev, ABS_X, x);
-               input_report_abs(input_dev, ABS_Y, y);
-               input_report_abs(input_dev, ABS_PRESSURE, Rt);
-               input_sync(input_dev);
                return 0;
        }
 
index ccde586025632671d5ea6279b89a3602262600a3..2ca9e5d6646028c428ec06fd525ad971629d98a2 100644 (file)
@@ -514,7 +514,7 @@ err_free_irq:
 err_cs_disable:
        pdata->cs_dis(pdata->cs_pin);
 err_free_mem:
-       input_free_device(bu21013_data->in_dev);
+       input_free_device(in_dev);
        kfree(bu21013_data);
 
        return error;
index 40b914bded8c2a3237abca74d295d8d80a02b2e3..2e72227bd071b9d18329e60a0e4b06a444700ec9 100644 (file)
@@ -1427,8 +1427,8 @@ modeisar(struct BCState *bcs, int mode, int bc)
                                        &bcs->hw.isar.reg->Flags))
                                        bcs->hw.isar.dpath = 1;
                                else {
-                                       printk(KERN_WARNING"isar modeisar analog funktions only with DP1\n");
-                                       debugl1(cs, "isar modeisar analog funktions only with DP1");
+                                       printk(KERN_WARNING"isar modeisar analog functions only with DP1\n");
+                                       debugl1(cs, "isar modeisar analog functions only with DP1");
                                        return(1);
                                }
                                break;
index 3063f591f0dca0e0eb809bb4b490039d8bcf2943..1739557a903881a246c14d5047cca5a454081894 100644 (file)
@@ -92,3 +92,5 @@ unmap:
 }
 
 arch_initcall(soekris_init);
+
+MODULE_LICENSE("GPL");
index 647d52b1a1b75d3a38390d3ec3c9588abca28ac2..f60107c3b091b966895e48f6e1860112bbaa3482 100644 (file)
@@ -389,6 +389,8 @@ static int ir_getkeycode(struct input_dev *dev,
        ke->len = sizeof(entry->scancode);
        memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));
 
+       retval = 0;
+
 out:
        spin_unlock_irqrestore(&rc_tab->lock, flags);
        return retval;
index 43579b3b24acce4e23caac9e9ce1d2f2f811af44..53363108994ee93bed670940b0eb91170a389456 100644 (file)
@@ -3043,7 +3043,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
        atl1_pcie_patch(adapter);
        /* assume we have no link for now */
        netif_carrier_off(netdev);
-       netif_stop_queue(netdev);
 
        setup_timer(&adapter->phy_config_timer, atl1_phy_config,
                    (unsigned long)adapter);
index 9eea225decaf724e7d88243fc8c462c62020f81e..863e73a85fbe0ef4cd48ebac5cd5e95846397ebc 100644 (file)
@@ -20,8 +20,8 @@
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.60.00-3"
-#define DRV_MODULE_RELDATE      "2010/10/19"
+#define DRV_MODULE_VERSION      "1.60.00-4"
+#define DRV_MODULE_RELDATE      "2010/11/01"
 #define BNX2X_BC_VER            0x040200
 
 #define BNX2X_MULTI_QUEUE
index 18c8e23a0e82fafaabe0183700960a194c9524af..4cfd4e9b5586f1740d547b02aa8f86e756c86033 100644 (file)
@@ -244,7 +244,14 @@ struct port_hw_cfg {                           /* port 0: 0x12c  port 1: 0x2bc */
 
        u16 xgxs_config_tx[4];                              /* 0x1A0 */
 
-       u32 Reserved1[57];                                  /* 0x1A8 */
+       u32 Reserved1[56];                                  /* 0x1A8 */
+       u32 default_cfg;                                    /* 0x288 */
+       /*  Enable BAM on KR */
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_MASK                    0x00100000
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_SHIFT                   20
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_DISABLED                0x00000000
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED                 0x00100000
+
        u32 speed_capability_mask2;                         /* 0x28C */
 #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_MASK                0x0000FFFF
 #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_SHIFT               0
index 2326774df843841315d783dfa6c53a073a2ef4b5..580919619252e3d0594f5365226bc295a8efcba9 100644 (file)
@@ -610,7 +610,7 @@ static u8 bnx2x_bmac_enable(struct link_params *params,
        /* reset and unreset the BigMac */
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
                     (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
-       udelay(10);
+       msleep(1);
 
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
                     (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
@@ -3525,13 +3525,19 @@ static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
        DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
 
        /* Enable CL37 BAM */
-       bnx2x_cl45_read(bp, phy,
-                       MDIO_AN_DEVAD,
-                       MDIO_AN_REG_8073_BAM, &val);
-       bnx2x_cl45_write(bp, phy,
-                        MDIO_AN_DEVAD,
-                        MDIO_AN_REG_8073_BAM, val | 1);
+       if (REG_RD(bp, params->shmem_base +
+                        offsetof(struct shmem_region, dev_info.
+                                 port_hw_config[params->port].default_cfg)) &
+           PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) {
 
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_AN_DEVAD,
+                               MDIO_AN_REG_8073_BAM, &val);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD,
+                                MDIO_AN_REG_8073_BAM, val | 1);
+               DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n");
+       }
        if (params->loopback_mode == LOOPBACK_EXT) {
                bnx2x_807x_force_10G(bp, phy);
                DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
@@ -5302,7 +5308,7 @@ static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
 {
        struct bnx2x *bp = params->bp;
        u16 autoneg_val, an_1000_val, an_10_100_val;
-       bnx2x_wait_reset_complete(bp, phy);
+
        bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
                      1 << NIG_LATCH_BC_ENABLE_MI_INT);
 
@@ -5431,6 +5437,7 @@ static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
 
        /* HW reset */
        bnx2x_ext_phy_hw_reset(bp, params->port);
+       bnx2x_wait_reset_complete(bp, phy);
 
        bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
        return bnx2x_848xx_cmn_config_init(phy, params, vars);
@@ -5441,7 +5448,7 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
                                  struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
-       u8 port = params->port, initialize = 1;
+       u8 port, initialize = 1;
        u16 val;
        u16 temp;
        u32 actual_phy_selection;
@@ -5450,11 +5457,16 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
        /* This is just for MDIO_CTL_REG_84823_MEDIA register. */
 
        msleep(1);
+       if (CHIP_IS_E2(bp))
+               port = BP_PATH(bp);
+       else
+               port = params->port;
        bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
                       MISC_REGISTERS_GPIO_OUTPUT_HIGH,
                       port);
-       msleep(200); /* 100 is not enough */
-
+       bnx2x_wait_reset_complete(bp, phy);
+       /* Wait for GPHY to come out of reset */
+       msleep(50);
        /* BCM84823 requires that XGXS links up first @ 10G for normal
        behavior */
        temp = vars->line_speed;
@@ -5625,7 +5637,11 @@ static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
                                   struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
-       u8 port = params->port;
+       u8 port;
+       if (CHIP_IS_E2(bp))
+               port = BP_PATH(bp);
+       else
+               port = params->port;
        bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
                            MISC_REGISTERS_GPIO_OUTPUT_LOW,
                            port);
@@ -6928,7 +6944,7 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
                  u8 reset_ext_phy)
 {
        struct bnx2x *bp = params->bp;
-       u8 phy_index, port = params->port;
+       u8 phy_index, port = params->port, clear_latch_ind = 0;
        DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
        /* disable attentions */
        vars->link_status = 0;
@@ -6966,9 +6982,18 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
                                params->phy[phy_index].link_reset(
                                        &params->phy[phy_index],
                                        params);
+                       if (params->phy[phy_index].flags &
+                           FLAGS_REARM_LATCH_SIGNAL)
+                               clear_latch_ind = 1;
                }
        }
 
+       if (clear_latch_ind) {
+               /* Clear latching indication */
+               bnx2x_rearm_latch_signal(bp, port, 0);
+               bnx2x_bits_dis(bp, NIG_REG_LATCH_BC_0 + port*4,
+                              1 << NIG_LATCH_BC_ENABLE_MI_INT);
+       }
        if (params->phy[INT_PHY].link_reset)
                params->phy[INT_PHY].link_reset(
                        &params->phy[INT_PHY], params);
@@ -6999,6 +7024,7 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
        s8 port;
        s8 port_of_path = 0;
 
+       bnx2x_ext_phy_hw_reset(bp, 0);
        /* PART1 - Reset both phys */
        for (port = PORT_MAX - 1; port >= PORT_0; port--) {
                u32 shmem_base, shmem2_base;
@@ -7021,7 +7047,8 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
                        return -EINVAL;
                }
                /* disable attentions */
-               bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+               bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
+                              port_of_path*4,
                             (NIG_MASK_XGXS0_LINK_STATUS |
                              NIG_MASK_XGXS0_LINK10G |
                              NIG_MASK_SERDES0_LINK_STATUS |
@@ -7132,7 +7159,7 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp,
                (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
        REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
 
-       bnx2x_ext_phy_hw_reset(bp, 1);
+       bnx2x_ext_phy_hw_reset(bp, 0);
        msleep(5);
        for (port = 0; port < PORT_MAX; port++) {
                u32 shmem_base, shmem2_base;
index 8427533fe313c35cb38727e533cd77dd35cdb4af..8b4cea57a6c5c47f585f5fcae935771e575dcd18 100644 (file)
@@ -33,6 +33,9 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>");
 MODULE_DESCRIPTION("CAIF SPI driver");
 
+/* Returns the number of padding bytes for alignment. */
+#define PAD_POW2(x, pow) ((((x)&((pow)-1))==0) ? 0 : (((pow)-((x)&((pow)-1)))))
+
 static int spi_loop;
 module_param(spi_loop, bool, S_IRUGO);
 MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
@@ -41,7 +44,10 @@ MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
 module_param(spi_frm_align, int, S_IRUGO);
 MODULE_PARM_DESC(spi_frm_align, "SPI frame alignment.");
 
-/* SPI padding options. */
+/*
+ * SPI padding options.
+ * Warning: must be a base of 2 (& operation used) and can not be zero !
+ */
 module_param(spi_up_head_align, int, S_IRUGO);
 MODULE_PARM_DESC(spi_up_head_align, "SPI uplink head alignment.");
 
@@ -240,15 +246,13 @@ static ssize_t dbgfs_frame(struct file *file, char __user *user_buf,
 static const struct file_operations dbgfs_state_fops = {
        .open = dbgfs_open,
        .read = dbgfs_state,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
+       .owner = THIS_MODULE
 };
 
 static const struct file_operations dbgfs_frame_fops = {
        .open = dbgfs_open,
        .read = dbgfs_frame,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
+       .owner = THIS_MODULE
 };
 
 static inline void dev_debugfs_add(struct cfspi *cfspi)
@@ -337,6 +341,9 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
        u8 *dst = buf;
        caif_assert(buf);
 
+       if (cfspi->slave && !cfspi->slave_talked)
+               cfspi->slave_talked = true;
+
        do {
                struct sk_buff *skb;
                struct caif_payload_info *info;
@@ -357,8 +364,8 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
                 * Compute head offset i.e. number of bytes to add to
                 * get the start of the payload aligned.
                 */
-               if (spi_up_head_align) {
-                       spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+               if (spi_up_head_align > 1) {
+                       spad = 1 + PAD_POW2((info->hdr_len + 1), spi_up_head_align);
                        *dst = (u8)(spad - 1);
                        dst += spad;
                }
@@ -373,7 +380,7 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
                 * Compute tail offset i.e. number of bytes to add to
                 * get the complete CAIF frame aligned.
                 */
-               epad = (skb->len + spad) & spi_up_tail_align;
+               epad = PAD_POW2((skb->len + spad), spi_up_tail_align);
                dst += epad;
 
                dev_kfree_skb(skb);
@@ -417,14 +424,14 @@ int cfspi_xmitlen(struct cfspi *cfspi)
                 * Compute head offset i.e. number of bytes to add to
                 * get the start of the payload aligned.
                 */
-               if (spi_up_head_align)
-                       spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+               if (spi_up_head_align > 1)
+                       spad = 1 + PAD_POW2((info->hdr_len + 1), spi_up_head_align);
 
                /*
                 * Compute tail offset i.e. number of bytes to add to
                 * get the complete CAIF frame aligned.
                 */
-               epad = (skb->len + spad) & spi_up_tail_align;
+               epad = PAD_POW2((skb->len + spad), spi_up_tail_align);
 
                if ((skb->len + spad + epad + frm_len) <= CAIF_MAX_SPI_FRAME) {
                        skb_queue_tail(&cfspi->chead, skb);
@@ -433,6 +440,7 @@ int cfspi_xmitlen(struct cfspi *cfspi)
                } else {
                        /* Put back packet. */
                        skb_queue_head(&cfspi->qhead, skb);
+                       break;
                }
        } while (pkts <= CAIF_MAX_SPI_PKTS);
 
@@ -453,6 +461,15 @@ static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
 {
        struct cfspi *cfspi = (struct cfspi *)ifc->priv;
 
+       /*
+        * The slave device is the master on the link. Interrupts before the
+        * slave has transmitted are considered spurious.
+        */
+       if (cfspi->slave && !cfspi->slave_talked) {
+               printk(KERN_WARNING "CFSPI: Spurious SS interrupt.\n");
+               return;
+       }
+
        if (!in_interrupt())
                spin_lock(&cfspi->lock);
        if (assert) {
@@ -465,7 +482,8 @@ static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
                spin_unlock(&cfspi->lock);
 
        /* Wake up the xfer thread. */
-       wake_up_interruptible(&cfspi->wait);
+       if (assert)
+               wake_up_interruptible(&cfspi->wait);
 }
 
 static void cfspi_xfer_done_cb(struct cfspi_ifc *ifc)
@@ -523,7 +541,7 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
                 * Compute head offset i.e. number of bytes added to
                 * get the start of the payload aligned.
                 */
-               if (spi_down_head_align) {
+               if (spi_down_head_align > 1) {
                        spad = 1 + *src;
                        src += spad;
                }
@@ -564,7 +582,7 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
                 * Compute tail offset i.e. number of bytes added to
                 * get the complete CAIF frame aligned.
                 */
-               epad = (pkt_len + spad) & spi_down_tail_align;
+               epad = PAD_POW2((pkt_len + spad), spi_down_tail_align);
                src += epad;
        } while ((src - buf) < len);
 
@@ -625,11 +643,20 @@ int cfspi_spi_probe(struct platform_device *pdev)
        cfspi->ndev = ndev;
        cfspi->pdev = pdev;
 
-       /* Set flow info */
+       /* Set flow info. */
        cfspi->flow_off_sent = 0;
        cfspi->qd_low_mark = LOW_WATER_MARK;
        cfspi->qd_high_mark = HIGH_WATER_MARK;
 
+       /* Set slave info. */
+       if (!strncmp(cfspi_spi_driver.driver.name, "cfspi_sspi", 10)) {
+               cfspi->slave = true;
+               cfspi->slave_talked = false;
+       } else {
+               cfspi->slave = false;
+               cfspi->slave_talked = false;
+       }
+
        /* Assign the SPI device. */
        cfspi->dev = dev;
        /* Assign the device ifc to this SPI interface. */
index 2111dbfea6feb8b53f56e73567e54fd4d11a818b..1b9943a4edabb8f48678d7384ac2141d47264908 100644 (file)
@@ -36,10 +36,15 @@ static inline int forward_to_spi_cmd(struct cfspi *cfspi)
 #endif
 
 int spi_frm_align = 2;
-int spi_up_head_align = 1;
-int spi_up_tail_align;
-int spi_down_head_align = 3;
-int spi_down_tail_align = 1;
+
+/*
+ * SPI padding options.
+ * Warning: must be a base of 2 (& operation used) and can not be zero !
+ */
+int spi_up_head_align   = 1 << 1;
+int spi_up_tail_align   = 1 << 0;
+int spi_down_head_align = 1 << 2;
+int spi_down_tail_align = 1 << 1;
 
 #ifdef CONFIG_DEBUG_FS
 static inline void debugfs_store_prev(struct cfspi *cfspi)
index 407d4e2720750246356af4cf7fd627fe9cad3d91..046d846c652dc4c807bb79b9ee5ffe343368919d 100644 (file)
@@ -3341,7 +3341,6 @@ static int __devinit init_one(struct pci_dev *pdev,
                                adapter->name = adapter->port[i]->name;
 
                        __set_bit(i, &adapter->registered_device_map);
-                       netif_tx_stop_all_queues(adapter->port[i]);
                }
        }
        if (!adapter->registered_device_map) {
index f17703f410b3673a096aec05f9085329650c5c52..f50bc98310f8b319cf8cdfe1f1b63a23fff19e72 100644 (file)
@@ -3736,7 +3736,6 @@ static int __devinit init_one(struct pci_dev *pdev,
 
                        __set_bit(i, &adapter->registered_device_map);
                        adapter->chan_map[adap2pinfo(adapter, i)->tx_chan] = i;
-                       netif_tx_stop_all_queues(adapter->port[i]);
                }
        }
        if (!adapter->registered_device_map) {
index 555ecc5a2e939b25028ac6a61cf2792da379caa7..6de5e2e448a5671afcdbb441e3810531690ddfb0 100644 (file)
@@ -2600,7 +2600,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
                pi->xact_addr_filt = -1;
                pi->rx_offload = RX_CSO;
                netif_carrier_off(netdev);
-               netif_tx_stop_all_queues(netdev);
                netdev->irq = pdev->irq;
 
                netdev->features = (NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
index 385dc3204cb7eefbbaa184f0601267abe7c392ee..06bb9b7994585318bb723046a0804a39a4a4a5e8 100644 (file)
@@ -2871,7 +2871,6 @@ static int __devinit emac_probe(struct platform_device *ofdev,
        SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops);
 
        netif_carrier_off(ndev);
-       netif_stop_queue(ndev);
 
        err = register_netdev(ndev);
        if (err) {
index d85edf3119c2625d999b22a41b6159ba9ebf7a24..c57d9a43cecacbf8a668a0c4b1cca5e7b93c3521 100644 (file)
@@ -2955,11 +2955,7 @@ jme_init_one(struct pci_dev *pdev,
         * Tell stack that we are not ready to work until open()
         */
        netif_carrier_off(netdev);
-       netif_stop_queue(netdev);
 
-       /*
-        * Register netdev
-        */
        rc = register_netdev(netdev);
        if (rc) {
                pr_err("Cannot register net device\n");
index a75ba9517404d94ca7c3da59472cfb80a57025c6..e1d30d7f207121a5de4636fd85b8bf7d9b76acb5 100644 (file)
@@ -41,9 +41,6 @@
 MODULE_DESCRIPTION("QLogic/NetXen (1/10) GbE Converged Ethernet Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(NETXEN_NIC_LINUX_VERSIONID);
-MODULE_FIRMWARE(NX_P2_MN_ROMIMAGE_NAME);
-MODULE_FIRMWARE(NX_P3_CT_ROMIMAGE_NAME);
-MODULE_FIRMWARE(NX_P3_MN_ROMIMAGE_NAME);
 MODULE_FIRMWARE(NX_UNIFIED_ROMIMAGE_NAME);
 
 char netxen_nic_driver_name[] = "netxen_nic";
index 7a298cdf9ab398135b2f59df9c7ad642c8f8840b..a3dcd04be22f6291e2546f84e474cef31e7fae34 100644 (file)
@@ -1450,7 +1450,6 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
        netdev->irq = adapter->msix_entries[0].vector;
 
        netif_carrier_off(netdev);
-       netif_stop_queue(netdev);
 
        err = register_netdev(netdev);
        if (err) {
index 52f38e12a879db9d344fb80f169f05eba31fa860..50f712e99e9634d2a348ba497a146b3d86c9dfde 100644 (file)
@@ -22,7 +22,7 @@
 #define __SMSC911X_H__
 
 #define TX_FIFO_LOW_THRESHOLD  ((u32)1600)
-#define SMSC911X_EEPROM_SIZE   ((u32)7)
+#define SMSC911X_EEPROM_SIZE   ((u32)128)
 #define USE_DEBUG              0
 
 /* This is the maximum number of packets to be received every
index 28e1ffb13db99df5b0537a7426b2af3c03980feb..c78a50586c1d86a0fffa9a59ab461a1996da8122 100644 (file)
@@ -2021,7 +2021,6 @@ static int __devinit de_init_one (struct pci_dev *pdev,
        de->media_timer.data = (unsigned long) de;
 
        netif_carrier_off(dev);
-       netif_stop_queue(dev);
 
        /* wake up device, assign resources */
        rc = pci_enable_device(pdev);
index ca7fc9df1ccf900533d56c35326b360316283af2..c04d49e31f814fe11d2f1b730dcba014afeb324c 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/usb/usbnet.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
+#include <linux/pm_runtime.h>
 
 #define DRIVER_VERSION         "22-Aug-2005"
 
@@ -1273,6 +1274,16 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
        struct usb_device               *xdev;
        int                             status;
        const char                      *name;
+       struct usb_driver       *driver = to_usb_driver(udev->dev.driver);
+
+       /* usbnet already took usb runtime pm, so have to enable the feature
+        * for usb interface, otherwise usb_autopm_get_interface may return
+        * failure if USB_SUSPEND(RUNTIME_PM) is enabled.
+        */
+       if (!driver->supports_autosuspend) {
+               driver->supports_autosuspend = 1;
+               pm_runtime_enable(&udev->dev);
+       }
 
        name = udev->dev.driver->name;
        info = (struct driver_info *) prod->driver_info;
index 32dee2ce5d3177706f8bc7394794952a87389324..d5ef696298eed37db811f55e60c0b7f3c0ded6f6 100644 (file)
@@ -54,6 +54,7 @@
 
 #define DRV_DESCRIPTION "802.11 data/management/control stack"
 #define DRV_NAME        "libipw"
+#define DRV_PROCNAME   "ieee80211"
 #define DRV_VERSION    LIBIPW_VERSION
 #define DRV_COPYRIGHT   "Copyright (C) 2004-2005 Intel Corporation <jketreno@linux.intel.com>"
 
@@ -293,16 +294,16 @@ static int __init libipw_init(void)
        struct proc_dir_entry *e;
 
        libipw_debug_level = debug;
-       libipw_proc = proc_mkdir("ieee80211", init_net.proc_net);
+       libipw_proc = proc_mkdir(DRV_PROCNAME, init_net.proc_net);
        if (libipw_proc == NULL) {
-               LIBIPW_ERROR("Unable to create " DRV_NAME
+               LIBIPW_ERROR("Unable to create " DRV_PROCNAME
                                " proc directory\n");
                return -EIO;
        }
        e = proc_create("debug_level", S_IRUGO | S_IWUSR, libipw_proc,
                        &debug_level_proc_fops);
        if (!e) {
-               remove_proc_entry(DRV_NAME, init_net.proc_net);
+               remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
                libipw_proc = NULL;
                return -EIO;
        }
@@ -319,7 +320,7 @@ static void __exit libipw_exit(void)
 #ifdef CONFIG_LIBIPW_DEBUG
        if (libipw_proc) {
                remove_proc_entry("debug_level", libipw_proc);
-               remove_proc_entry(DRV_NAME, init_net.proc_net);
+               remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
                libipw_proc = NULL;
        }
 #endif                         /* CONFIG_LIBIPW_DEBUG */
index 359d1e04626cb938784290a5700058a3115d7b34..f0d63892264410b23e19753885868cca81071eda 100644 (file)
@@ -35,7 +35,7 @@
 
 #ifdef CONFIG_SH_SECUREEDGE5410
 #include <asm/rtc.h>
-#include <mach/snapgear.h>
+#include <mach/secureedge5410.h>
 
 #define        RTC_RESET       0x1000
 #define        RTC_IODATA      0x0800
index 938d5036016687d06267d3fab991eb841e122e20..b464ae01086cfef7773814c765418f81863e695e 100644 (file)
@@ -270,7 +270,7 @@ void zfcp_fc_eval_fcp_rsp(struct fcp_resp_with_ext *fcp_rsp,
        if (unlikely(rsp_flags & FCP_SNS_LEN_VAL)) {
                sense = (char *) &fcp_rsp[1];
                if (rsp_flags & FCP_RSP_LEN_VAL)
-                       sense += fcp_rsp->ext.fr_sns_len;
+                       sense += fcp_rsp->ext.fr_rsp_len;
                sense_len = min(fcp_rsp->ext.fr_sns_len,
                                (u32) SCSI_SENSE_BUFFERSIZE);
                memcpy(scsi->sense_buffer, sense, sense_len);
index beaf0916ceab73e627c95931aa6186ab3df7dd55..be0317457147fc4a891f4b0be67c8116b98526b1 100644 (file)
@@ -532,9 +532,6 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
                fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
                adapter->hydra_version = 0;
 
-               atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
-                               &adapter->status);
-
                zfcp_fsf_link_down_info_eval(req,
                        &qtcb->header.fsf_status_qual.link_down_info);
                break;
index 1119c535a667318381409eee3626bc2dcb85f1fa..20796ebc33cec3435cb5b2a2de297580e534fb8c 100644 (file)
@@ -142,6 +142,8 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
                return -ENOMEM;
        }
 
+       get_device(&port->dev);
+
        if (device_register(&unit->dev)) {
                put_device(&unit->dev);
                return -ENOMEM;
@@ -152,8 +154,6 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
                return -EINVAL;
        }
 
-       get_device(&port->dev);
-
        write_lock_irq(&port->unit_list_lock);
        list_add_tail(&unit->list, &port->unit_list);
        write_unlock_irq(&port->unit_list_lock);
index ceaac65a91ff4f9cae03ea55197c2266948b5d21..ff2bd07161f746a1c3dee089807628b6fe90a840 100644 (file)
@@ -29,13 +29,13 @@ struct bfa_s;
 typedef void (*bfa_isr_func_t) (struct bfa_s *bfa, struct bfi_msg_s *m);
 typedef void    (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete);
 
-/**
+/*
  * Interrupt message handlers
  */
 void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m);
 void bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func);
 
-/**
+/*
  * Request and response queue related defines
  */
 #define BFA_REQQ_NELEMS_MIN    (4)
@@ -58,9 +58,9 @@ void bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func);
 #define bfa_reqq_produce(__bfa, __reqq)        do {                            \
                (__bfa)->iocfc.req_cq_pi[__reqq]++;                     \
                (__bfa)->iocfc.req_cq_pi[__reqq] &=                     \
-                       ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1);      \
-               bfa_reg_write((__bfa)->iocfc.bfa_regs.cpe_q_pi[__reqq], \
-                             (__bfa)->iocfc.req_cq_pi[__reqq]);      \
+                       ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1); \
+               writel((__bfa)->iocfc.req_cq_pi[__reqq],                \
+                       (__bfa)->iocfc.bfa_regs.cpe_q_pi[__reqq]);      \
                mmiowb();      \
        } while (0)
 
@@ -76,7 +76,7 @@ void bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func);
        (__index) &= ((__size) - 1);                    \
 } while (0)
 
-/**
+/*
  * Queue element to wait for room in request queue. FIFO order is
  * maintained when fullfilling requests.
  */
@@ -86,7 +86,7 @@ struct bfa_reqq_wait_s {
        void            *cbarg;
 };
 
-/**
+/*
  * Circular queue usage assignments
  */
 enum {
@@ -113,7 +113,7 @@ bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg),
 
 #define bfa_reqq(__bfa, __reqq)        (&(__bfa)->reqq_waitq[__reqq])
 
-/**
+/*
  * static inline void
  * bfa_reqq_wait(struct bfa_s *bfa, int reqq, struct bfa_reqq_wait_s *wqe)
  */
@@ -130,7 +130,7 @@ bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg),
 #define bfa_reqq_wcancel(__wqe)        list_del(&(__wqe)->qe)
 
 
-/**
+/*
  * Generic BFA callback element.
  */
 struct bfa_cb_qe_s {
@@ -163,7 +163,7 @@ struct bfa_cb_qe_s {
        } while (0)
 
 
-/**
+/*
  * PCI devices supported by the current BFA
  */
 struct bfa_pciid_s {
@@ -173,7 +173,7 @@ struct bfa_pciid_s {
 
 extern char     bfa_version[];
 
-/**
+/*
  * BFA memory resources
  */
 enum bfa_mem_type {
@@ -202,19 +202,19 @@ struct bfa_meminfo_s {
        ((_m)->meminfo[BFA_MEM_TYPE_DMA - 1].dma_curp)
 
 struct bfa_iocfc_regs_s {
-       bfa_os_addr_t   intr_status;
-       bfa_os_addr_t   intr_mask;
-       bfa_os_addr_t   cpe_q_pi[BFI_IOC_MAX_CQS];
-       bfa_os_addr_t   cpe_q_ci[BFI_IOC_MAX_CQS];
-       bfa_os_addr_t   cpe_q_depth[BFI_IOC_MAX_CQS];
-       bfa_os_addr_t   cpe_q_ctrl[BFI_IOC_MAX_CQS];
-       bfa_os_addr_t   rme_q_ci[BFI_IOC_MAX_CQS];
-       bfa_os_addr_t   rme_q_pi[BFI_IOC_MAX_CQS];
-       bfa_os_addr_t   rme_q_depth[BFI_IOC_MAX_CQS];
-       bfa_os_addr_t   rme_q_ctrl[BFI_IOC_MAX_CQS];
+       void __iomem    *intr_status;
+       void __iomem    *intr_mask;
+       void __iomem    *cpe_q_pi[BFI_IOC_MAX_CQS];
+       void __iomem    *cpe_q_ci[BFI_IOC_MAX_CQS];
+       void __iomem    *cpe_q_depth[BFI_IOC_MAX_CQS];
+       void __iomem    *cpe_q_ctrl[BFI_IOC_MAX_CQS];
+       void __iomem    *rme_q_ci[BFI_IOC_MAX_CQS];
+       void __iomem    *rme_q_pi[BFI_IOC_MAX_CQS];
+       void __iomem    *rme_q_depth[BFI_IOC_MAX_CQS];
+       void __iomem    *rme_q_ctrl[BFI_IOC_MAX_CQS];
 };
 
-/**
+/*
  * MSIX vector handlers
  */
 #define BFA_MSIX_MAX_VECTORS   22
@@ -224,7 +224,7 @@ struct bfa_msix_s {
        bfa_msix_handler_t handler[BFA_MSIX_MAX_VECTORS];
 };
 
-/**
+/*
  * Chip specific interfaces
  */
 struct bfa_hwif_s {
@@ -343,7 +343,7 @@ int bfa_iocfc_get_pbc_vports(struct bfa_s *bfa,
                                struct bfi_pbc_vport_s *pbc_vport);
 
 
-/**
+/*
  *----------------------------------------------------------------------
  *             BFA public interfaces
  *----------------------------------------------------------------------
index a989a94c38da3f43238bbb875d65c22b9dec2629..6f021015f1f67c14fd400b38a2669683db73661b 100644 (file)
@@ -37,18 +37,18 @@ bfad_int_to_lun(u32 luno)
        } lun;
 
        lun.bfa_lun     = 0;
-       lun.scsi_lun[0] = bfa_os_htons(luno);
+       lun.scsi_lun[0] = cpu_to_be16(luno);
 
        return lun.bfa_lun;
 }
 
-/**
+/*
  * Get LUN for the I/O request
  */
 #define bfa_cb_ioim_get_lun(__dio)     \
        bfad_int_to_lun(((struct scsi_cmnd *)__dio)->device->lun)
 
-/**
+/*
  * Get CDB for the I/O request
  */
 static inline u8 *
@@ -59,7 +59,7 @@ bfa_cb_ioim_get_cdb(struct bfad_ioim_s *dio)
        return (u8 *) cmnd->cmnd;
 }
 
-/**
+/*
  * Get I/O direction (read/write) for the I/O request
  */
 static inline enum fcp_iodir
@@ -77,7 +77,7 @@ bfa_cb_ioim_get_iodir(struct bfad_ioim_s *dio)
                return FCP_IODIR_NONE;
 }
 
-/**
+/*
  * Get IO size in bytes for the I/O request
  */
 static inline u32
@@ -88,7 +88,7 @@ bfa_cb_ioim_get_size(struct bfad_ioim_s *dio)
        return scsi_bufflen(cmnd);
 }
 
-/**
+/*
  * Get timeout for the I/O request
  */
 static inline u8
@@ -104,7 +104,7 @@ bfa_cb_ioim_get_timeout(struct bfad_ioim_s *dio)
        return 0;
 }
 
-/**
+/*
  * Get Command Reference Number for the I/O request. 0 if none.
  */
 static inline u8
@@ -113,7 +113,7 @@ bfa_cb_ioim_get_crn(struct bfad_ioim_s *dio)
        return 0;
 }
 
-/**
+/*
  * Get SAM-3 priority for the I/O request. 0 is default.
  */
 static inline u8
@@ -122,7 +122,7 @@ bfa_cb_ioim_get_priority(struct bfad_ioim_s *dio)
        return 0;
 }
 
-/**
+/*
  * Get task attributes for the I/O request. Default is FCP_TASK_ATTR_SIMPLE(0).
  */
 static inline u8
@@ -148,7 +148,7 @@ bfa_cb_ioim_get_taskattr(struct bfad_ioim_s *dio)
        return task_attr;
 }
 
-/**
+/*
  * Get CDB length in bytes for the I/O request. Default is FCP_CMND_CDB_LEN(16).
  */
 static inline u8
@@ -159,7 +159,7 @@ bfa_cb_ioim_get_cdblen(struct bfad_ioim_s *dio)
        return cmnd->cmd_len;
 }
 
-/**
+/*
  * Assign queue to be used for the I/O request. This value depends on whether
  * the driver wants to use the queues via any specific algorithm. Currently,
  * this is not supported.
index c2fa07f2485dc909bc7910efa925ee8c01bcb877..2345f48dc57fc9a3940665d75b11a3a205f22b16 100644 (file)
 
 BFA_TRC_FILE(HAL, CORE);
 
-/**
+/*
  * BFA IOC FC related definitions
  */
 
-/**
+/*
  * IOC local definitions
  */
 #define BFA_IOCFC_TOV          5000    /* msecs */
@@ -54,7 +54,7 @@ enum {
 #define DEF_CFG_NUM_SBOOT_TGTS         16
 #define DEF_CFG_NUM_SBOOT_LUNS         16
 
-/**
+/*
  * forward declaration for IOC FC functions
  */
 static void bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status);
@@ -63,7 +63,7 @@ static void bfa_iocfc_hbfail_cbfn(void *bfa_arg);
 static void bfa_iocfc_reset_cbfn(void *bfa_arg);
 static struct bfa_ioc_cbfn_s bfa_iocfc_cbfn;
 
-/**
+/*
  * BFA Interrupt handling functions
  */
 static void
@@ -86,7 +86,7 @@ bfa_reqq_resume(struct bfa_s *bfa, int qid)
 
        waitq = bfa_reqq(bfa, qid);
        list_for_each_safe(qe, qen, waitq) {
-               /**
+               /*
                 * Callback only as long as there is room in request queue
                 */
                if (bfa_reqq_full(bfa, qid))
@@ -104,7 +104,7 @@ bfa_msix_all(struct bfa_s *bfa, int vec)
        bfa_intx(bfa);
 }
 
-/**
+/*
  *  hal_intr_api
  */
 bfa_boolean_t
@@ -113,15 +113,15 @@ bfa_intx(struct bfa_s *bfa)
        u32 intr, qintr;
        int queue;
 
-       intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status);
+       intr = readl(bfa->iocfc.bfa_regs.intr_status);
        if (!intr)
                return BFA_FALSE;
 
-       /**
+       /*
         * RME completion queue interrupt
         */
        qintr = intr & __HFN_INT_RME_MASK;
-       bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr);
+       writel(qintr, bfa->iocfc.bfa_regs.intr_status);
 
        for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) {
                if (intr & (__HFN_INT_RME_Q0 << queue))
@@ -131,11 +131,11 @@ bfa_intx(struct bfa_s *bfa)
        if (!intr)
                return BFA_TRUE;
 
-       /**
+       /*
         * CPE completion queue interrupt
         */
        qintr = intr & __HFN_INT_CPE_MASK;
-       bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr);
+       writel(qintr, bfa->iocfc.bfa_regs.intr_status);
 
        for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) {
                if (intr & (__HFN_INT_CPE_Q0 << queue))
@@ -153,13 +153,13 @@ bfa_intx(struct bfa_s *bfa)
 void
 bfa_intx_enable(struct bfa_s *bfa)
 {
-       bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, bfa->iocfc.intr_mask);
+       writel(bfa->iocfc.intr_mask, bfa->iocfc.bfa_regs.intr_mask);
 }
 
 void
 bfa_intx_disable(struct bfa_s *bfa)
 {
-       bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, -1L);
+       writel(-1L, bfa->iocfc.bfa_regs.intr_mask);
 }
 
 void
@@ -188,8 +188,8 @@ bfa_isr_enable(struct bfa_s *bfa)
                                __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 |
                                __HFN_INT_MBOX_LPU1);
 
-       bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr_unmask);
-       bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, ~intr_unmask);
+       writel(intr_unmask, bfa->iocfc.bfa_regs.intr_status);
+       writel(~intr_unmask, bfa->iocfc.bfa_regs.intr_mask);
        bfa->iocfc.intr_mask = ~intr_unmask;
        bfa_isr_mode_set(bfa, bfa->msix.nvecs != 0);
 }
@@ -198,7 +198,7 @@ void
 bfa_isr_disable(struct bfa_s *bfa)
 {
        bfa_isr_mode_set(bfa, BFA_FALSE);
-       bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, -1L);
+       writel(-1L, bfa->iocfc.bfa_regs.intr_mask);
        bfa_msix_uninstall(bfa);
 }
 
@@ -211,7 +211,7 @@ bfa_msix_reqq(struct bfa_s *bfa, int qid)
 
        bfa->iocfc.hwif.hw_reqq_ack(bfa, qid);
 
-       /**
+       /*
         * Resume any pending requests in the corresponding reqq.
         */
        waitq = bfa_reqq(bfa, qid);
@@ -259,14 +259,14 @@ bfa_msix_rspq(struct bfa_s *bfa, int qid)
                }
        }
 
-       /**
+       /*
         * update CI
         */
        bfa_rspq_ci(bfa, qid) = pi;
-       bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ci[qid], pi);
+       writel(pi, bfa->iocfc.bfa_regs.rme_q_ci[qid]);
        mmiowb();
 
-       /**
+       /*
         * Resume any pending requests in the corresponding reqq.
         */
        waitq = bfa_reqq(bfa, qid);
@@ -279,7 +279,7 @@ bfa_msix_lpu_err(struct bfa_s *bfa, int vec)
 {
        u32 intr, curr_value;
 
-       intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status);
+       intr = readl(bfa->iocfc.bfa_regs.intr_status);
 
        if (intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1))
                bfa_msix_lpu(bfa);
@@ -289,30 +289,30 @@ bfa_msix_lpu_err(struct bfa_s *bfa, int vec)
 
        if (intr) {
                if (intr & __HFN_INT_LL_HALT) {
-                       /**
+                       /*
                         * If LL_HALT bit is set then FW Init Halt LL Port
                         * Register needs to be cleared as well so Interrupt
                         * Status Register will be cleared.
                         */
-                       curr_value = bfa_reg_read(bfa->ioc.ioc_regs.ll_halt);
+                       curr_value = readl(bfa->ioc.ioc_regs.ll_halt);
                        curr_value &= ~__FW_INIT_HALT_P;
-                       bfa_reg_write(bfa->ioc.ioc_regs.ll_halt, curr_value);
+                       writel(curr_value, bfa->ioc.ioc_regs.ll_halt);
                }
 
                if (intr & __HFN_INT_ERR_PSS) {
-                       /**
+                       /*
                         * ERR_PSS bit needs to be cleared as well in case
                         * interrups are shared so driver's interrupt handler is
                         * still called eventhough it is already masked out.
                         */
-                       curr_value = bfa_reg_read(
+                       curr_value = readl(
                                        bfa->ioc.ioc_regs.pss_err_status_reg);
                        curr_value &= __PSS_ERR_STATUS_SET;
-                       bfa_reg_write(bfa->ioc.ioc_regs.pss_err_status_reg,
-                                       curr_value);
+                       writel(curr_value,
+                               bfa->ioc.ioc_regs.pss_err_status_reg);
                }
 
-               bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr);
+               writel(intr, bfa->iocfc.bfa_regs.intr_status);
                bfa_msix_errint(bfa, intr);
        }
 }
@@ -323,11 +323,11 @@ bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func)
        bfa_isrs[mc] = isr_func;
 }
 
-/**
+/*
  * BFA IOC FC related functions
  */
 
-/**
+/*
  *  hal_ioc_pvt BFA IOC private functions
  */
 
@@ -366,7 +366,7 @@ bfa_iocfc_fw_cfg_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len)
                            BFA_CACHELINE_SZ);
 }
 
-/**
+/*
  * Use the Mailbox interface to send BFI_IOCFC_H2I_CFG_REQ
  */
 static void
@@ -384,14 +384,14 @@ bfa_iocfc_send_cfg(void *bfa_arg)
 
        bfa_iocfc_reset_queues(bfa);
 
-       /**
+       /*
         * initialize IOC configuration info
         */
        cfg_info->endian_sig = BFI_IOC_ENDIAN_SIG;
        cfg_info->num_cqs = cfg->fwcfg.num_cqs;
 
        bfa_dma_be_addr_set(cfg_info->cfgrsp_addr, iocfc->cfgrsp_dma.pa);
-       /**
+       /*
         * dma map REQ and RSP circular queues and shadow pointers
         */
        for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
@@ -400,17 +400,17 @@ bfa_iocfc_send_cfg(void *bfa_arg)
                bfa_dma_be_addr_set(cfg_info->req_shadow_ci[i],
                                    iocfc->req_cq_shadow_ci[i].pa);
                cfg_info->req_cq_elems[i] =
-                       bfa_os_htons(cfg->drvcfg.num_reqq_elems);
+                       cpu_to_be16(cfg->drvcfg.num_reqq_elems);
 
                bfa_dma_be_addr_set(cfg_info->rsp_cq_ba[i],
                                    iocfc->rsp_cq_ba[i].pa);
                bfa_dma_be_addr_set(cfg_info->rsp_shadow_pi[i],
                                    iocfc->rsp_cq_shadow_pi[i].pa);
                cfg_info->rsp_cq_elems[i] =
-                       bfa_os_htons(cfg->drvcfg.num_rspq_elems);
+                       cpu_to_be16(cfg->drvcfg.num_rspq_elems);
        }
 
-       /**
+       /*
         * Enable interrupt coalescing if it is driver init path
         * and not ioc disable/enable path.
         */
@@ -419,7 +419,7 @@ bfa_iocfc_send_cfg(void *bfa_arg)
 
        iocfc->cfgdone = BFA_FALSE;
 
-       /**
+       /*
         * dma map IOC configuration itself
         */
        bfi_h2i_set(cfg_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CFG_REQ,
@@ -440,9 +440,9 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
        iocfc->bfa = bfa;
        iocfc->action = BFA_IOCFC_ACT_NONE;
 
-       bfa_os_assign(iocfc->cfg, *cfg);
+       iocfc->cfg = *cfg;
 
-       /**
+       /*
         * Initialize chip specific handlers.
         */
        if (bfa_asic_id_ct(bfa_ioc_devid(&bfa->ioc))) {
@@ -503,13 +503,13 @@ bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg,
        for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
                iocfc->req_cq_ba[i].kva = dm_kva;
                iocfc->req_cq_ba[i].pa = dm_pa;
-               bfa_os_memset(dm_kva, 0, per_reqq_sz);
+               memset(dm_kva, 0, per_reqq_sz);
                dm_kva += per_reqq_sz;
                dm_pa += per_reqq_sz;
 
                iocfc->rsp_cq_ba[i].kva = dm_kva;
                iocfc->rsp_cq_ba[i].pa = dm_pa;
-               bfa_os_memset(dm_kva, 0, per_rspq_sz);
+               memset(dm_kva, 0, per_rspq_sz);
                dm_kva += per_rspq_sz;
                dm_pa += per_rspq_sz;
        }
@@ -559,7 +559,7 @@ bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg,
        }
 }
 
-/**
+/*
  * Start BFA submodules.
  */
 static void
@@ -573,7 +573,7 @@ bfa_iocfc_start_submod(struct bfa_s *bfa)
                hal_mods[i]->start(bfa);
 }
 
-/**
+/*
  * Disable BFA submodules.
  */
 static void
@@ -623,7 +623,7 @@ bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t compl)
                complete(&bfad->disable_comp);
 }
 
-/**
+/*
  * Update BFA configuration from firmware configuration.
  */
 static void
@@ -634,15 +634,15 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa)
        struct bfa_iocfc_fwcfg_s        *fwcfg   = &cfgrsp->fwcfg;
 
        fwcfg->num_cqs        = fwcfg->num_cqs;
-       fwcfg->num_ioim_reqs  = bfa_os_ntohs(fwcfg->num_ioim_reqs);
-       fwcfg->num_tskim_reqs = bfa_os_ntohs(fwcfg->num_tskim_reqs);
-       fwcfg->num_fcxp_reqs  = bfa_os_ntohs(fwcfg->num_fcxp_reqs);
-       fwcfg->num_uf_bufs    = bfa_os_ntohs(fwcfg->num_uf_bufs);
-       fwcfg->num_rports     = bfa_os_ntohs(fwcfg->num_rports);
+       fwcfg->num_ioim_reqs  = be16_to_cpu(fwcfg->num_ioim_reqs);
+       fwcfg->num_tskim_reqs = be16_to_cpu(fwcfg->num_tskim_reqs);
+       fwcfg->num_fcxp_reqs  = be16_to_cpu(fwcfg->num_fcxp_reqs);
+       fwcfg->num_uf_bufs    = be16_to_cpu(fwcfg->num_uf_bufs);
+       fwcfg->num_rports     = be16_to_cpu(fwcfg->num_rports);
 
        iocfc->cfgdone = BFA_TRUE;
 
-       /**
+       /*
         * Configuration is complete - initialize/start submodules
         */
        bfa_fcport_init(bfa);
@@ -665,7 +665,7 @@ bfa_iocfc_reset_queues(struct bfa_s *bfa)
        }
 }
 
-/**
+/*
  * IOC enable request is complete
  */
 static void
@@ -684,7 +684,7 @@ bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status)
        bfa_iocfc_send_cfg(bfa);
 }
 
-/**
+/*
  * IOC disable request is complete
  */
 static void
@@ -705,7 +705,7 @@ bfa_iocfc_disable_cbfn(void *bfa_arg)
        }
 }
 
-/**
+/*
  * Notify sub-modules of hardware failure.
  */
 static void
@@ -723,7 +723,7 @@ bfa_iocfc_hbfail_cbfn(void *bfa_arg)
                             bfa);
 }
 
-/**
+/*
  * Actions on chip-reset completion.
  */
 static void
@@ -735,11 +735,11 @@ bfa_iocfc_reset_cbfn(void *bfa_arg)
        bfa_isr_enable(bfa);
 }
 
-/**
+/*
  *  hal_ioc_public
  */
 
-/**
+/*
  * Query IOC memory requirement information.
  */
 void
@@ -754,7 +754,7 @@ bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
        *km_len += bfa_ioc_debug_trcsz(bfa_auto_recover);
 }
 
-/**
+/*
  * Query IOC memory requirement information.
  */
 void
@@ -772,7 +772,7 @@ bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
        ioc->trcmod = bfa->trcmod;
        bfa_ioc_attach(&bfa->ioc, bfa, &bfa_iocfc_cbfn, &bfa->timer_mod);
 
-       /**
+       /*
         * Set FC mode for BFA_PCI_DEVICE_ID_CT_FC.
         */
        if (pcidev->device_id == BFA_PCI_DEVICE_ID_CT_FC)
@@ -790,7 +790,7 @@ bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
                INIT_LIST_HEAD(&bfa->reqq_waitq[i]);
 }
 
-/**
+/*
  * Query IOC memory requirement information.
  */
 void
@@ -799,7 +799,7 @@ bfa_iocfc_detach(struct bfa_s *bfa)
        bfa_ioc_detach(&bfa->ioc);
 }
 
-/**
+/*
  * Query IOC memory requirement information.
  */
 void
@@ -809,7 +809,7 @@ bfa_iocfc_init(struct bfa_s *bfa)
        bfa_ioc_enable(&bfa->ioc);
 }
 
-/**
+/*
  * IOC start called from bfa_start(). Called to start IOC operations
  * at driver instantiation for this instance.
  */
@@ -820,7 +820,7 @@ bfa_iocfc_start(struct bfa_s *bfa)
                bfa_iocfc_start_submod(bfa);
 }
 
-/**
+/*
  * IOC stop called from bfa_stop(). Called only when driver is unloaded
  * for this instance.
  */
@@ -876,12 +876,12 @@ bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr)
        attr->intr_attr.coalesce = iocfc->cfginfo->intr_attr.coalesce;
 
        attr->intr_attr.delay = iocfc->cfginfo->intr_attr.delay ?
-                               bfa_os_ntohs(iocfc->cfginfo->intr_attr.delay) :
-                               bfa_os_ntohs(iocfc->cfgrsp->intr_attr.delay);
+                               be16_to_cpu(iocfc->cfginfo->intr_attr.delay) :
+                               be16_to_cpu(iocfc->cfgrsp->intr_attr.delay);
 
        attr->intr_attr.latency = iocfc->cfginfo->intr_attr.latency ?
-                       bfa_os_ntohs(iocfc->cfginfo->intr_attr.latency) :
-                       bfa_os_ntohs(iocfc->cfgrsp->intr_attr.latency);
+                       be16_to_cpu(iocfc->cfginfo->intr_attr.latency) :
+                       be16_to_cpu(iocfc->cfgrsp->intr_attr.latency);
 
        attr->config    = iocfc->cfg;
 }
@@ -893,8 +893,8 @@ bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr)
        struct bfi_iocfc_set_intr_req_s *m;
 
        iocfc->cfginfo->intr_attr.coalesce = attr->coalesce;
-       iocfc->cfginfo->intr_attr.delay = bfa_os_htons(attr->delay);
-       iocfc->cfginfo->intr_attr.latency = bfa_os_htons(attr->latency);
+       iocfc->cfginfo->intr_attr.delay = cpu_to_be16(attr->delay);
+       iocfc->cfginfo->intr_attr.latency = cpu_to_be16(attr->latency);
 
        if (!bfa_iocfc_is_operational(bfa))
                return BFA_STATUS_OK;
@@ -924,7 +924,7 @@ bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa)
        iocfc->cfginfo->sense_buf_len = (BFI_IOIM_SNSLEN - 1);
        bfa_dma_be_addr_set(iocfc->cfginfo->ioim_snsbase, snsbase_pa);
 }
-/**
+/*
  * Enable IOC after it is disabled.
  */
 void
@@ -953,7 +953,7 @@ bfa_iocfc_is_operational(struct bfa_s *bfa)
        return bfa_ioc_is_operational(&bfa->ioc) && bfa->iocfc.cfgdone;
 }
 
-/**
+/*
  * Return boot target port wwns -- read from boot information in flash.
  */
 void
@@ -998,11 +998,11 @@ bfa_iocfc_get_pbc_vports(struct bfa_s *bfa, struct bfi_pbc_vport_s *pbc_vport)
        return cfgrsp->pbc_cfg.nvports;
 }
 
-/**
+/*
  *  hal_api
  */
 
-/**
+/*
  * Use this function query the memory requirement of the BFA library.
  * This function needs to be called before bfa_attach() to get the
  * memory required of the BFA layer for a given driver configuration.
@@ -1038,7 +1038,7 @@ bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo)
 
        bfa_assert((cfg != NULL) && (meminfo != NULL));
 
-       bfa_os_memset((void *)meminfo, 0, sizeof(struct bfa_meminfo_s));
+       memset((void *)meminfo, 0, sizeof(struct bfa_meminfo_s));
        meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_type =
                BFA_MEM_TYPE_KVA;
        meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_type =
@@ -1055,7 +1055,7 @@ bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo)
        meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_len = dm_len;
 }
 
-/**
+/*
  * Use this function to do attach the driver instance with the BFA
  * library. This function will not trigger any HW initialization
  * process (which will be done in bfa_init() call)
@@ -1092,7 +1092,7 @@ bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
 
        bfa_assert((cfg != NULL) && (meminfo != NULL));
 
-       /**
+       /*
         * initialize all memory pointers for iterative allocation
         */
        for (i = 0; i < BFA_MEM_TYPE_MAX; i++) {
@@ -1109,7 +1109,7 @@ bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
        bfa_com_port_attach(bfa, meminfo);
 }
 
-/**
+/*
  * Use this function to delete a BFA IOC. IOC should be stopped (by
  * calling bfa_stop()) before this function call.
  *
@@ -1146,7 +1146,7 @@ bfa_init_plog(struct bfa_s *bfa, struct bfa_plog_s *plog)
        bfa->plog = plog;
 }
 
-/**
+/*
  * Initialize IOC.
  *
  * This function will return immediately, when the IOC initialization is
@@ -1169,7 +1169,7 @@ bfa_init(struct bfa_s *bfa)
        bfa_iocfc_init(bfa);
 }
 
-/**
+/*
  * Use this function initiate the IOC configuration setup. This function
  * will return immediately.
  *
@@ -1183,7 +1183,7 @@ bfa_start(struct bfa_s *bfa)
        bfa_iocfc_start(bfa);
 }
 
-/**
+/*
  * Use this function quiese the IOC. This function will return immediately,
  * when the IOC is actually stopped, the bfad->comp will be set.
  *
@@ -1243,7 +1243,7 @@ bfa_attach_fcs(struct bfa_s *bfa)
        bfa->fcs = BFA_TRUE;
 }
 
-/**
+/*
  * Periodic timer heart beat from driver
  */
 void
@@ -1252,7 +1252,7 @@ bfa_timer_tick(struct bfa_s *bfa)
        bfa_timer_beat(&bfa->timer_mod);
 }
 
-/**
+/*
  * Return the list of PCI vendor/device id lists supported by this
  * BFA instance.
  */
@@ -1270,7 +1270,7 @@ bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids)
        *pciids = __pciids;
 }
 
-/**
+/*
  * Use this function query the default struct bfa_iocfc_cfg_s value (compiled
  * into BFA layer). The OS driver can then turn back and overwrite entries that
  * have been configured by the user.
@@ -1328,7 +1328,7 @@ bfa_get_attr(struct bfa_s *bfa, struct bfa_ioc_attr_s *ioc_attr)
        bfa_ioc_get_attr(&bfa->ioc, ioc_attr);
 }
 
-/**
+/*
  * Retrieve firmware trace information on IOC failure.
  */
 bfa_status_t
@@ -1337,7 +1337,7 @@ bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen)
        return bfa_ioc_debug_fwsave(&bfa->ioc, trcdata, trclen);
 }
 
-/**
+/*
  * Clear the saved firmware trace information of an IOC.
  */
 void
@@ -1346,7 +1346,7 @@ bfa_debug_fwsave_clear(struct bfa_s *bfa)
        bfa_ioc_debug_fwsave_clear(&bfa->ioc);
 }
 
-/**
+/*
  * Fetch firmware trace data.
  *
  * @param[in]          bfa                     BFA instance
@@ -1362,7 +1362,7 @@ bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen)
        return bfa_ioc_debug_fwtrc(&bfa->ioc, trcdata, trclen);
 }
 
-/**
+/*
  * Dump firmware memory.
  *
  * @param[in]          bfa             BFA instance
@@ -1378,7 +1378,7 @@ bfa_debug_fwcore(struct bfa_s *bfa, void *buf, u32 *offset, int *buflen)
 {
        return bfa_ioc_debug_fwcore(&bfa->ioc, buf, offset, buflen);
 }
-/**
+/*
  * Reset hw semaphore & usage cnt regs and initialize.
  */
 void
@@ -1388,7 +1388,7 @@ bfa_chip_reset(struct bfa_s *bfa)
        bfa_ioc_pll_init(&bfa->ioc);
 }
 
-/**
+/*
  * Fetch firmware statistics data.
  *
  * @param[in]          bfa             BFA instance
index 7260c74620f8fa5f2fd4cbe0060d1e87a326d6b4..99f242b9aa3110216fb93915338a86d8c22f7955 100644 (file)
@@ -15,7 +15,7 @@
  * General Public License for more details.
  */
 
-/**
+/*
  *  bfa_cs.h BFA common services
  */
 
@@ -24,7 +24,7 @@
 
 #include "bfa_os_inc.h"
 
-/**
+/*
  * BFA TRC
  */
 
@@ -73,7 +73,7 @@ enum {
 #define BFA_TRC_MOD_SH 10
 #define BFA_TRC_MOD(__mod)     ((BFA_TRC_ ## __mod) << BFA_TRC_MOD_SH)
 
-/**
+/*
  * Define a new tracing file (module). Module should match one defined above.
  */
 #define BFA_TRC_FILE(__mod, __submod)                                  \
@@ -155,7 +155,7 @@ __bfa_trc32(struct bfa_trc_mod_s *trcm, int fileno, int line, u32 data)
 #define bfa_trc_fp(_trcp, _data)
 #endif
 
-/**
+/*
  * @ BFA LOG interfaces
  */
 #define bfa_assert(__cond)     do {                                    \
@@ -249,13 +249,13 @@ bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe)
 #define bfa_q_is_on_q(_q, _qe)      \
        bfa_q_is_on_q_func(_q, (struct list_head *)(_qe))
 
-/**
+/*
  * @ BFA state machine interfaces
  */
 
 typedef void (*bfa_sm_t)(void *sm, int event);
 
-/**
+/*
  * oc - object class eg. bfa_ioc
  * st - state, eg. reset
  * otype - object type, eg. struct bfa_ioc_s
@@ -269,7 +269,7 @@ typedef void (*bfa_sm_t)(void *sm, int event);
 #define bfa_sm_get_state(_sm)          ((_sm)->sm)
 #define bfa_sm_cmp_state(_sm, _state)  ((_sm)->sm == (bfa_sm_t)(_state))
 
-/**
+/*
  * For converting from state machine function to state encoding.
  */
 struct bfa_sm_table_s {
@@ -279,12 +279,12 @@ struct bfa_sm_table_s {
 };
 #define BFA_SM(_sm)    ((bfa_sm_t)(_sm))
 
-/**
+/*
  * State machine with entry actions.
  */
 typedef void (*bfa_fsm_t)(void *fsm, int event);
 
-/**
+/*
  * oc - object class eg. bfa_ioc
  * st - state, eg. reset
  * otype - object type, eg. struct bfa_ioc_s
@@ -314,7 +314,7 @@ bfa_sm_to_state(struct bfa_sm_table_s *smt, bfa_sm_t sm)
        return smt[i].state;
 }
 
-/**
+/*
  * @ Generic wait counter.
  */
 
@@ -340,7 +340,7 @@ bfa_wc_down(struct bfa_wc_s *wc)
                wc->wc_resume(wc->wc_cbarg);
 }
 
-/**
+/*
  * Initialize a waiting counter.
  */
 static inline void
@@ -352,7 +352,7 @@ bfa_wc_init(struct bfa_wc_s *wc, bfa_wc_resume_t wc_resume, void *wc_cbarg)
        bfa_wc_up(wc);
 }
 
-/**
+/*
  * Wait for counter to reach zero
  */
 static inline void
index d49877ff5140a6856620a8d45831f4104d806d57..4b5b9e35abb9889e72824d01f5ddf361817fc7dd 100644 (file)
@@ -24,7 +24,7 @@
 #define BFA_MFG_SERIALNUM_SIZE                  11
 #define STRSZ(_n)                               (((_n) + 4) & ~3)
 
-/**
+/*
  * Manufacturing card type
  */
 enum {
@@ -45,7 +45,7 @@ enum {
 
 #pragma pack(1)
 
-/**
+/*
  * Check if Mezz card
  */
 #define bfa_mfg_is_mezz(type) (( \
@@ -55,7 +55,7 @@ enum {
        (type) == BFA_MFG_TYPE_LIGHTNING_P0 || \
        (type) == BFA_MFG_TYPE_LIGHTNING))
 
-/**
+/*
  * Check if the card having old wwn/mac handling
  */
 #define bfa_mfg_is_old_wwn_mac_model(type) (( \
@@ -78,12 +78,12 @@ do {                                                            \
        (m)[2] = t & 0xFF;                                      \
 } while (0)
 
-/**
+/*
  * VPD data length
  */
 #define BFA_MFG_VPD_LEN                 512
 
-/**
+/*
  * VPD vendor tag
  */
 enum {
@@ -97,7 +97,7 @@ enum {
        BFA_MFG_VPD_PCI_BRCD    = 0xf8,  /*  PCI VPD Brocade            */
 };
 
-/**
+/*
  * All numerical fields are in big-endian format.
  */
 struct bfa_mfg_vpd_s {
@@ -112,7 +112,7 @@ struct bfa_mfg_vpd_s {
 
 #pragma pack()
 
-/**
+/*
  * Status return values
  */
 enum bfa_status {
@@ -167,11 +167,11 @@ enum bfa_boolean {
 #define BFA_STRING_32  32
 #define BFA_VERSION_LEN 64
 
-/**
+/*
  * ---------------------- adapter definitions ------------
  */
 
-/**
+/*
  * BFA adapter level attributes.
  */
 enum {
@@ -215,7 +215,7 @@ struct bfa_adapter_attr_s {
        u8              trunk_capable;
 };
 
-/**
+/*
  * ---------------------- IOC definitions ------------
  */
 
@@ -224,7 +224,7 @@ enum {
        BFA_IOC_CHIP_REV_LEN    = 8,
 };
 
-/**
+/*
  * Driver and firmware versions.
  */
 struct bfa_ioc_driver_attr_s {
@@ -236,7 +236,7 @@ struct bfa_ioc_driver_attr_s {
        char            ob_ver[BFA_VERSION_LEN];        /*  openboot version */
 };
 
-/**
+/*
  * IOC PCI device attributes
  */
 struct bfa_ioc_pci_attr_s {
@@ -249,7 +249,7 @@ struct bfa_ioc_pci_attr_s {
        char            chip_rev[BFA_IOC_CHIP_REV_LEN];  /*  chip revision */
 };
 
-/**
+/*
  * IOC states
  */
 enum bfa_ioc_state {
@@ -267,7 +267,7 @@ enum bfa_ioc_state {
        BFA_IOC_ENABLING        = 12,   /*  IOC is being enabled */
 };
 
-/**
+/*
  * IOC firmware stats
  */
 struct bfa_fw_ioc_stats_s {
@@ -279,7 +279,7 @@ struct bfa_fw_ioc_stats_s {
        u32     unknown_reqs;
 };
 
-/**
+/*
  * IOC driver stats
  */
 struct bfa_ioc_drv_stats_s {
@@ -296,7 +296,7 @@ struct bfa_ioc_drv_stats_s {
        u32     enable_replies;
 };
 
-/**
+/*
  * IOC statistics
  */
 struct bfa_ioc_stats_s {
@@ -310,7 +310,7 @@ enum bfa_ioc_type_e {
        BFA_IOC_TYPE_LL         = 3,
 };
 
-/**
+/*
  * IOC attributes returned in queries
  */
 struct bfa_ioc_attr_s {
@@ -323,11 +323,11 @@ struct bfa_ioc_attr_s {
        u8                              rsvd[7];        /*  64bit align    */
 };
 
-/**
+/*
  * ---------------------- mfg definitions ------------
  */
 
-/**
+/*
  * Checksum size
  */
 #define BFA_MFG_CHKSUM_SIZE                    16
@@ -340,7 +340,7 @@ struct bfa_ioc_attr_s {
 
 #pragma pack(1)
 
-/**
+/*
  * All numerical fields are in big-endian format.
  */
 struct bfa_mfg_block_s {
@@ -373,11 +373,11 @@ struct bfa_mfg_block_s {
 
 #pragma pack()
 
-/**
+/*
  * ---------------------- pci definitions ------------
  */
 
-/**
+/*
  * PCI device and vendor ID information
  */
 enum {
@@ -392,14 +392,14 @@ enum {
        ((devid) == BFA_PCI_DEVICE_ID_CT ||     \
         (devid) == BFA_PCI_DEVICE_ID_CT_FC)
 
-/**
+/*
  * PCI sub-system device and vendor ID information
  */
 enum {
        BFA_PCI_FCOE_SSDEVICE_ID        = 0x14,
 };
 
-/**
+/*
  * Maximum number of device address ranges mapped through different BAR(s)
  */
 #define BFA_PCI_ACCESS_RANGES 1
@@ -430,7 +430,7 @@ enum {
 #define BOOT_CFG_REV1   1
 #define BOOT_CFG_VLAN   1
 
-/**
+/*
  *      Boot options setting. Boot options setting determines from where
  *      to get the boot lun information
  */
@@ -442,7 +442,7 @@ enum bfa_boot_bootopt {
 };
 
 #pragma pack(1)
-/**
+/*
  * Boot lun information.
  */
 struct bfa_boot_bootlun_s {
@@ -451,7 +451,7 @@ struct bfa_boot_bootlun_s {
 };
 #pragma pack()
 
-/**
+/*
  * BOOT boot configuraton
  */
 struct bfa_boot_pbc_s {
index 96905d301828f90b3060752661e5d247c54fa18a..191d34a58b9cf15e5167b419832fc287b0201779 100644 (file)
@@ -21,7 +21,7 @@
 #include "bfa_fc.h"
 #include "bfa_defs_svc.h"
 
-/**
+/*
  * VF states
  */
 enum bfa_vf_state {
@@ -35,7 +35,7 @@ enum bfa_vf_state {
        BFA_VF_ISOLATED  = 7,   /*  port isolated due to vf_id mismatch */
 };
 
-/**
+/*
  * VF statistics
  */
 struct bfa_vf_stats_s {
@@ -55,7 +55,7 @@ struct bfa_vf_stats_s {
        u32     resvd; /*  padding for 64 bit alignment */
 };
 
-/**
+/*
  * VF attributes returned in queries
  */
 struct bfa_vf_attr_s {
@@ -67,7 +67,7 @@ struct bfa_vf_attr_s {
 #define BFA_FCS_MAX_LPORTS 256
 #define BFA_FCS_FABRIC_IPADDR_SZ  16
 
-/**
+/*
  * symbolic names for base port/virtual port
  */
 #define BFA_SYMNAME_MAXLEN     128     /* 128 bytes */
@@ -75,7 +75,7 @@ struct bfa_lport_symname_s {
        char        symname[BFA_SYMNAME_MAXLEN];
 };
 
-/**
+/*
 * Roles of FCS port:
  *     - FCP IM and FCP TM roles cannot be enabled together for a FCS port
  *     - Create multiple ports if both IM and TM functions required.
@@ -86,19 +86,19 @@ enum bfa_lport_role {
        BFA_LPORT_ROLE_FCP_MAX  = BFA_LPORT_ROLE_FCP_IM,
 };
 
-/**
+/*
  * FCS port configuration.
  */
 struct bfa_lport_cfg_s {
     wwn_t             pwwn;       /*  port wwn */
     wwn_t             nwwn;       /*  node wwn */
     struct bfa_lport_symname_s  sym_name;   /*  vm port symbolic name */
-       bfa_boolean_t       preboot_vp;  /*  vport created from PBC */
+    bfa_boolean_t       preboot_vp;  /*  vport created from PBC */
     enum bfa_lport_role     roles;      /*  FCS port roles */
     u8      tag[16];   /*  opaque tag from application */
 };
 
-/**
+/*
  * FCS port states
  */
 enum bfa_lport_state {
@@ -108,7 +108,7 @@ enum bfa_lport_state {
        BFA_LPORT_OFFLINE = 3,  /*  No login to fabric */
 };
 
-/**
+/*
  * FCS port type.
  */
 enum bfa_lport_type {
@@ -116,7 +116,7 @@ enum bfa_lport_type {
        BFA_LPORT_TYPE_VIRTUAL,
 };
 
-/**
+/*
  * FCS port offline reason.
  */
 enum bfa_lport_offline_reason {
@@ -128,7 +128,7 @@ enum bfa_lport_offline_reason {
        BFA_LPORT_OFFLINE_FAB_LOGOUT,
 };
 
-/**
+/*
  * FCS lport info.
  */
 struct bfa_lport_info_s {
@@ -150,7 +150,7 @@ struct bfa_lport_info_s {
 
 };
 
-/**
+/*
  * FCS port statistics
  */
 struct bfa_lport_stats_s {
@@ -222,7 +222,7 @@ struct bfa_lport_stats_s {
                                            * (max retry of plogi) */
 };
 
-/**
+/*
  * BFA port attribute returned in queries
  */
 struct bfa_lport_attr_s {
@@ -239,7 +239,7 @@ struct bfa_lport_attr_s {
 };
 
 
-/**
+/*
  * VPORT states
  */
 enum bfa_vport_state {
@@ -258,7 +258,7 @@ enum bfa_vport_state {
        BFA_FCS_VPORT_MAX_STATE,
 };
 
-/**
+/*
  * vport statistics
  */
 struct bfa_vport_stats_s {
@@ -296,7 +296,7 @@ struct bfa_vport_stats_s {
        u32        rsvd;
 };
 
-/**
+/*
  * BFA vport attribute returned in queries
  */
 struct bfa_vport_attr_s {
@@ -305,7 +305,7 @@ struct bfa_vport_attr_s {
        u32          rsvd;
 };
 
-/**
+/*
  * FCS remote port states
  */
 enum bfa_rport_state {
@@ -321,7 +321,7 @@ enum bfa_rport_state {
        BFA_RPORT_NSDISC        = 9,    /*  re-discover rport */
 };
 
-/**
+/*
  *  Rport Scsi Function : Initiator/Target.
  */
 enum bfa_rport_function {
@@ -329,7 +329,7 @@ enum bfa_rport_function {
        BFA_RPORT_TARGET        = 0x02, /*  SCSI Target */
 };
 
-/**
+/*
  * port/node symbolic names for rport
  */
 #define BFA_RPORT_SYMNAME_MAXLEN       255
@@ -337,7 +337,7 @@ struct bfa_rport_symname_s {
        char            symname[BFA_RPORT_SYMNAME_MAXLEN];
 };
 
-/**
+/*
  * FCS remote port statistics
  */
 struct bfa_rport_stats_s {
@@ -374,7 +374,7 @@ struct bfa_rport_stats_s {
        struct bfa_rport_hal_stats_s    hal_stats;  /*  BFA rport stats    */
 };
 
-/**
+/*
  * FCS remote port attributes returned in queries
  */
 struct bfa_rport_attr_s {
@@ -411,7 +411,7 @@ struct bfa_rport_remote_link_stats_s {
 #define BFA_MAX_IO_INDEX 7
 #define BFA_NO_IO_INDEX 9
 
-/**
+/*
  * FCS itnim states
  */
 enum bfa_itnim_state {
@@ -425,7 +425,7 @@ enum bfa_itnim_state {
        BFA_ITNIM_INITIATIOR    = 7,    /*  initiator */
 };
 
-/**
+/*
  * FCS remote port statistics
  */
 struct bfa_itnim_stats_s {
@@ -443,7 +443,7 @@ struct bfa_itnim_stats_s {
        u32     rsvd;           /* padding for 64 bit alignment */
 };
 
-/**
+/*
  * FCS itnim attributes returned in queries
  */
 struct bfa_itnim_attr_s {
index 56226fcf9470e167b71eb3f9cc5b8136d8bfb6db..e24e9f7ca81ff0b68f0b6ea2383f374a73d47165 100644 (file)
@@ -27,7 +27,7 @@
 #define BFA_IOCFCOE_INTR_DELAY 25
 #define BFA_IOCFCOE_INTR_LATENCY 5
 
-/**
+/*
  * Interrupt coalescing configuration.
  */
 #pragma pack(1)
@@ -38,7 +38,7 @@ struct bfa_iocfc_intr_attr_s {
        u16     delay;          /*  delay in microseconds     */
 };
 
-/**
+/*
  * IOC firmware configuraton
  */
 struct bfa_iocfc_fwcfg_s {
@@ -71,7 +71,7 @@ struct bfa_iocfc_drvcfg_s {
        u32             rsvd;
 };
 
-/**
+/*
  * IOC configuration
  */
 struct bfa_iocfc_cfg_s {
@@ -79,7 +79,7 @@ struct bfa_iocfc_cfg_s {
        struct bfa_iocfc_drvcfg_s       drvcfg; /*  driver side config    */
 };
 
-/**
+/*
  * IOC firmware IO stats
  */
 struct bfa_fw_io_stats_s {
@@ -152,7 +152,7 @@ struct bfa_fw_io_stats_s {
                                                 */
 };
 
-/**
+/*
  * IOC port firmware stats
  */
 
@@ -262,7 +262,7 @@ struct bfa_fw_fcoe_stats_s {
     u32    mac_invalids;       /*  Invalid mac assigned                */
 };
 
-/**
+/*
  * IOC firmware FCoE port stats
  */
 struct bfa_fw_fcoe_port_stats_s {
@@ -270,7 +270,7 @@ struct bfa_fw_fcoe_port_stats_s {
     struct bfa_fw_fip_stats_s   fip_stats;
 };
 
-/**
+/*
  * IOC firmware FC uport stats
  */
 struct bfa_fw_fc_uport_stats_s {
@@ -278,7 +278,7 @@ struct bfa_fw_fc_uport_stats_s {
        struct bfa_fw_port_lksm_stats_s         lksm_stats;
 };
 
-/**
+/*
  * IOC firmware FC port stats
  */
 union bfa_fw_fc_port_stats_s {
@@ -286,7 +286,7 @@ union bfa_fw_fc_port_stats_s {
        struct bfa_fw_fcoe_port_stats_s fcoe_stats;
 };
 
-/**
+/*
  * IOC firmware port stats
  */
 struct bfa_fw_port_stats_s {
@@ -295,7 +295,7 @@ struct bfa_fw_port_stats_s {
        union  bfa_fw_fc_port_stats_s           fc_port;
 };
 
-/**
+/*
  * fcxchg module statistics
  */
 struct bfa_fw_fcxchg_stats_s {
@@ -308,7 +308,7 @@ struct bfa_fw_lpsm_stats_s {
        u32     cls_tx;
 };
 
-/**
+/*
  *  Trunk statistics
  */
 struct bfa_fw_trunk_stats_s {
@@ -334,7 +334,7 @@ struct bfa_fw_advsm_stats_s {
        u32 elp_dropped;                /*  ELP dropped         */
 };
 
-/**
+/*
  * IOCFC firmware stats
  */
 struct bfa_fw_iocfc_stats_s {
@@ -345,7 +345,7 @@ struct bfa_fw_iocfc_stats_s {
        u32     set_intr_reqs;  /*  set interrupt reqs */
 };
 
-/**
+/*
  * IOC attributes returned in queries
  */
 struct bfa_iocfc_attr_s {
@@ -353,7 +353,7 @@ struct bfa_iocfc_attr_s {
        struct bfa_iocfc_intr_attr_s    intr_attr;      /*  interrupt attr */
 };
 
-/**
+/*
  * Eth_sndrcv mod stats
  */
 struct bfa_fw_eth_sndrcv_stats_s {
@@ -361,7 +361,7 @@ struct bfa_fw_eth_sndrcv_stats_s {
        u32     rsvd;           /*  64bit align    */
 };
 
-/**
+/*
  * CT MAC mod stats
  */
 struct bfa_fw_mac_mod_stats_s {
@@ -379,7 +379,7 @@ struct bfa_fw_mac_mod_stats_s {
        u32     rsvd;           /*  64bit align    */
 };
 
-/**
+/*
  * CT MOD stats
  */
 struct bfa_fw_ct_mod_stats_s {
@@ -391,7 +391,7 @@ struct bfa_fw_ct_mod_stats_s {
        u32     rsvd;           /*  64bit align    */
 };
 
-/**
+/*
  * IOC firmware stats
  */
 struct bfa_fw_stats_s {
@@ -412,7 +412,7 @@ struct bfa_fw_stats_s {
 #define BFA_IOCFC_PATHTOV_MAX  60
 #define BFA_IOCFC_QDEPTH_MAX   2000
 
-/**
+/*
  * QoS states
  */
 enum bfa_qos_state {
@@ -420,7 +420,7 @@ enum bfa_qos_state {
        BFA_QOS_OFFLINE = 2,            /*  QoS is offline */
 };
 
-/**
+/*
  * QoS  Priority levels.
  */
 enum bfa_qos_priority {
@@ -430,7 +430,7 @@ enum bfa_qos_priority {
        BFA_QOS_LOW  =  3,      /*  QoS Priority Level Low */
 };
 
-/**
+/*
  * QoS  bandwidth allocation for each priority level
  */
 enum bfa_qos_bw_alloc {
@@ -439,7 +439,7 @@ enum bfa_qos_bw_alloc {
        BFA_QOS_BW_LOW  =  10,  /*  bandwidth allocation for Low */
 };
 #pragma pack(1)
-/**
+/*
  * QoS attribute returned in QoS Query
  */
 struct bfa_qos_attr_s {
@@ -448,7 +448,7 @@ struct bfa_qos_attr_s {
        u32  total_bb_cr;               /*  Total BB Credits */
 };
 
-/**
+/*
  * These fields should be displayed only from the CLI.
  * There will be a separate BFAL API (get_qos_vc_attr ?)
  * to retrieve this.
@@ -471,7 +471,7 @@ struct bfa_qos_vc_attr_s {
                                                            * total_vc_count */
 };
 
-/**
+/*
  * QoS statistics
  */
 struct bfa_qos_stats_s {
@@ -489,7 +489,7 @@ struct bfa_qos_stats_s {
        u32     rsvd;               /* padding for 64 bit alignment */
 };
 
-/**
+/*
  * FCoE statistics
  */
 struct bfa_fcoe_stats_s {
@@ -540,7 +540,7 @@ struct bfa_fcoe_stats_s {
        u64     rxf_bcast_vlan; /*  Rx FCoE broadcast vlan frames   */
 };
 
-/**
+/*
  * QoS or FCoE stats (fcport stats excluding physical FC port stats)
  */
 union bfa_fcport_stats_u {
@@ -639,7 +639,7 @@ enum bfa_port_states {
        BFA_PORT_ST_MAX_STATE,
 };
 
-/**
+/*
  *     Port operational type (in sync with SNIA port type).
  */
 enum bfa_port_type {
@@ -651,7 +651,7 @@ enum bfa_port_type {
        BFA_PORT_TYPE_VPORT     = 22,   /*  NPIV - virtual port */
 };
 
-/**
+/*
  *     Port topology setting. A port's topology and fabric login status
  *     determine its operational type.
  */
@@ -662,7 +662,7 @@ enum bfa_port_topology {
        BFA_PORT_TOPOLOGY_AUTO = 3,     /*  auto topology selection */
 };
 
-/**
+/*
  *     Physical port loopback types.
  */
 enum bfa_port_opmode {
@@ -679,7 +679,7 @@ enum bfa_port_opmode {
        (_mode == BFA_PORT_OPMODE_LB_SLW) ||            \
        (_mode == BFA_PORT_OPMODE_LB_EXT))
 
-/**
+/*
  *     Port link state
  */
 enum bfa_port_linkstate {
@@ -687,7 +687,7 @@ enum bfa_port_linkstate {
        BFA_PORT_LINKDOWN       = 2,    /*  Physical port/Trunk link down */
 };
 
-/**
+/*
  *     Port link state reason code
  */
 enum bfa_port_linkstate_rsn {
@@ -733,7 +733,7 @@ enum bfa_port_linkstate_rsn {
        CEE_ISCSI_PRI_OVERLAP_FCOE_PRI          = 43
 };
 #pragma pack(1)
-/**
+/*
  *      Physical port configuration
  */
 struct bfa_port_cfg_s {
@@ -753,7 +753,7 @@ struct bfa_port_cfg_s {
 };
 #pragma pack()
 
-/**
+/*
  *     Port attribute values.
  */
 struct bfa_port_attr_s {
@@ -800,7 +800,7 @@ struct bfa_port_attr_s {
        u8                      rsvd1[6];
 };
 
-/**
+/*
  *           Port FCP mappings.
  */
 struct bfa_port_fcpmap_s {
@@ -815,7 +815,7 @@ struct bfa_port_fcpmap_s {
        char            luid[256];
 };
 
-/**
+/*
  *           Port RNID info.
  */
 struct bfa_port_rnid_s {
@@ -848,7 +848,7 @@ struct bfa_fcport_fcf_s {
        mac_t      mac;     /*  FCF mac           */
 };
 
-/**
+/*
  *     Trunk states for BCU/BFAL
  */
 enum bfa_trunk_state {
@@ -857,7 +857,7 @@ enum bfa_trunk_state {
        BFA_TRUNK_OFFLINE       = 2,    /*  Trunk is offline            */
 };
 
-/**
+/*
  *     VC attributes for trunked link
  */
 struct bfa_trunk_vc_attr_s {
@@ -867,7 +867,7 @@ struct bfa_trunk_vc_attr_s {
        u16 vc_credits[8];
 };
 
-/**
+/*
  *     Link state information
  */
 struct bfa_port_link_s {
@@ -959,7 +959,7 @@ struct bfa_rport_hal_stats_s {
        u32        rsvd;
 };
 #pragma pack(1)
-/**
+/*
  *  Rport's QoS attributes
  */
 struct bfa_rport_qos_attr_s {
@@ -987,7 +987,7 @@ struct bfa_itnim_ioprofile_s {
        struct bfa_itnim_latency_s io_latency;
 };
 
-/**
+/*
  * FC physical port statistics.
  */
 struct bfa_port_fc_stats_s {
@@ -1022,7 +1022,7 @@ struct bfa_port_fc_stats_s {
        u64     err_enc;        /*  Encoding err frame_8b10b    */
 };
 
-/**
+/*
  * Eth Physical Port statistics.
  */
 struct bfa_port_eth_stats_s {
@@ -1070,7 +1070,7 @@ struct bfa_port_eth_stats_s {
        u64     tx_iscsi_zero_pause; /*  Tx iSCSI zero pause    */
 };
 
-/**
+/*
  *              Port statistics.
  */
 union bfa_port_stats_u {
index 14127646dc54cdb811ff944b7bea9dc0c838d4ed..0222d7c88a9a269812e520037d1d81d1f39070bd 100644 (file)
@@ -17,7 +17,7 @@
 
 #include "bfa_modules.h"
 
-/**
+/*
  * BFA module list terminated by NULL
  */
 struct bfa_module_s *hal_mods[] = {
@@ -31,7 +31,7 @@ struct bfa_module_s *hal_mods[] = {
        NULL
 };
 
-/**
+/*
  * Message handlers for various modules.
  */
 bfa_isr_func_t  bfa_isrs[BFI_MC_MAX] = {
@@ -70,7 +70,7 @@ bfa_isr_func_t  bfa_isrs[BFI_MC_MAX] = {
 };
 
 
-/**
+/*
  * Message handlers for mailbox command classes
  */
 bfa_ioc_mbox_mcfunc_t  bfa_mbox_isrs[BFI_MC_MAX] = {
index 6eff705564eb5310d015e1e54a2b82db760a1c3b..e929d25b09e3083d3a095c974d48f4faa464d199 100644 (file)
@@ -1029,7 +1029,7 @@ struct link_e2e_beacon_req_s {
        struct link_e2e_beacon_param_s beacon_parm;
 };
 
-/**
+/*
  * If RPSC request is sent to the Domain Controller, the request is for
  * all the ports within that domain (TODO - I don't think FOS implements
  * this...).
@@ -1049,7 +1049,7 @@ struct fc_rpsc_acc_s {
        struct fc_rpsc_speed_info_s speed_info[1];
 };
 
-/**
+/*
  * If RPSC2 request is sent to the Domain Controller,
  */
 #define FC_BRCD_TOKEN    0x42524344
@@ -1094,7 +1094,7 @@ struct fc_rpsc2_acc_s {
     struct fc_rpsc2_port_info_s port_info[1];    /* port information */
 };
 
-/**
+/*
  * bit fields so that multiple classes can be specified
  */
 enum fc_cos {
@@ -1131,7 +1131,7 @@ struct fc_alpabm_s {
 #define FC_VF_ID_MAX     0xEFF
 #define FC_VF_ID_CTL     0xFEF /*  control VF_ID */
 
-/**
+/*
  * Virtual Fabric Tagging header format
  * @caution This is defined only in BIG ENDIAN format.
  */
@@ -1463,7 +1463,7 @@ struct fcgs_gidpn_resp_s {
        u32     dap:24; /* port identifier */
 };
 
-/**
+/*
  * RFT_ID
  */
 struct fcgs_rftid_req_s {
@@ -1472,7 +1472,7 @@ struct fcgs_rftid_req_s {
        u32     fc4_type[8];    /* fc4 types */
 };
 
-/**
+/*
  * RFF_ID : Register FC4 features.
  */
 
@@ -1487,7 +1487,7 @@ struct fcgs_rffid_req_s {
     u32    fc4_type:8;         /* corresponding FC4 Type */
 };
 
-/**
+/*
  * GID_FT Request
  */
 struct fcgs_gidft_req_s {
@@ -1497,7 +1497,7 @@ struct fcgs_gidft_req_s {
        u8      fc4_type;       /* FC_TYPE_FCP for SCSI devices */
 };             /* GID_FT Request */
 
-/**
+/*
  * GID_FT Response
  */
 struct fcgs_gidft_resp_s {
@@ -1506,7 +1506,7 @@ struct fcgs_gidft_resp_s {
        u32     pid:24; /* port identifier */
 };             /* GID_FT Response */
 
-/**
+/*
  * RSPN_ID
  */
 struct fcgs_rspnid_req_s {
@@ -1516,7 +1516,7 @@ struct fcgs_rspnid_req_s {
        u8              spn[256];       /* symbolic port name */
 };
 
-/**
+/*
  * RPN_ID
  */
 struct fcgs_rpnid_req_s {
@@ -1525,7 +1525,7 @@ struct fcgs_rpnid_req_s {
        wwn_t           port_name;
 };
 
-/**
+/*
  * RNN_ID
  */
 struct fcgs_rnnid_req_s {
@@ -1534,7 +1534,7 @@ struct fcgs_rnnid_req_s {
        wwn_t           node_name;
 };
 
-/**
+/*
  * RCS_ID
  */
 struct fcgs_rcsid_req_s {
@@ -1543,7 +1543,7 @@ struct fcgs_rcsid_req_s {
        u32     cos;
 };
 
-/**
+/*
  * RPT_ID
  */
 struct fcgs_rptid_req_s {
@@ -1553,7 +1553,7 @@ struct fcgs_rptid_req_s {
        u32     rsvd1:24;
 };
 
-/**
+/*
  * GA_NXT Request
  */
 struct fcgs_ganxt_req_s {
@@ -1561,7 +1561,7 @@ struct fcgs_ganxt_req_s {
        u32     port_id:24;
 };
 
-/**
+/*
  * GA_NXT Response
  */
 struct fcgs_ganxt_rsp_s {
index b7d2657ca82a2086d4b6ac492c94e3c7835b36c8..9c725314b513f203fc3d4cfbe667f6850568564c 100644 (file)
@@ -94,13 +94,13 @@ fcbuild_init(void)
         */
        plogi_tmpl.csp.verhi = FC_PH_VER_PH_3;
        plogi_tmpl.csp.verlo = FC_PH_VER_4_3;
-       plogi_tmpl.csp.bbcred = bfa_os_htons(0x0004);
+       plogi_tmpl.csp.bbcred = cpu_to_be16(0x0004);
        plogi_tmpl.csp.ciro = 0x1;
        plogi_tmpl.csp.cisc = 0x0;
        plogi_tmpl.csp.altbbcred = 0x0;
-       plogi_tmpl.csp.conseq = bfa_os_htons(0x00FF);
-       plogi_tmpl.csp.ro_bitmap = bfa_os_htons(0x0002);
-       plogi_tmpl.csp.e_d_tov = bfa_os_htonl(2000);
+       plogi_tmpl.csp.conseq = cpu_to_be16(0x00FF);
+       plogi_tmpl.csp.ro_bitmap = cpu_to_be16(0x0002);
+       plogi_tmpl.csp.e_d_tov = cpu_to_be32(2000);
 
        plogi_tmpl.class3.class_valid = 1;
        plogi_tmpl.class3.sequential = 1;
@@ -112,7 +112,7 @@ fcbuild_init(void)
         */
        prli_tmpl.command = FC_ELS_PRLI;
        prli_tmpl.pglen = 0x10;
-       prli_tmpl.pagebytes = bfa_os_htons(0x0014);
+       prli_tmpl.pagebytes = cpu_to_be16(0x0014);
        prli_tmpl.parampage.type = FC_TYPE_FCP;
        prli_tmpl.parampage.imagepair = 1;
        prli_tmpl.parampage.servparams.rxrdisab = 1;
@@ -137,7 +137,7 @@ fcbuild_init(void)
 static void
 fc_gs_fchdr_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u32 ox_id)
 {
-       bfa_os_memset(fchs, 0, sizeof(struct fchs_s));
+       memset(fchs, 0, sizeof(struct fchs_s));
 
        fchs->routing = FC_RTG_FC4_DEV_DATA;
        fchs->cat_info = FC_CAT_UNSOLICIT_CTRL;
@@ -148,9 +148,9 @@ fc_gs_fchdr_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u32 ox_id)
        fchs->rx_id = FC_RXID_ANY;
        fchs->d_id = (d_id);
        fchs->s_id = (s_id);
-       fchs->ox_id = bfa_os_htons(ox_id);
+       fchs->ox_id = cpu_to_be16(ox_id);
 
-       /**
+       /*
         * @todo no need to set ox_id for request
         *       no need to set rx_id for response
         */
@@ -159,16 +159,16 @@ fc_gs_fchdr_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u32 ox_id)
 void
 fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id)
 {
-       bfa_os_memcpy(fchs, &fc_els_req_tmpl, sizeof(struct fchs_s));
+       memcpy(fchs, &fc_els_req_tmpl, sizeof(struct fchs_s));
        fchs->d_id = (d_id);
        fchs->s_id = (s_id);
-       fchs->ox_id = bfa_os_htons(ox_id);
+       fchs->ox_id = cpu_to_be16(ox_id);
 }
 
 static void
 fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id)
 {
-       bfa_os_memcpy(fchs, &fc_els_rsp_tmpl, sizeof(struct fchs_s));
+       memcpy(fchs, &fc_els_rsp_tmpl, sizeof(struct fchs_s));
        fchs->d_id = d_id;
        fchs->s_id = s_id;
        fchs->ox_id = ox_id;
@@ -198,7 +198,7 @@ fc_els_rsp_parse(struct fchs_s *fchs, int len)
 static void
 fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id)
 {
-       bfa_os_memcpy(fchs, &fc_bls_rsp_tmpl, sizeof(struct fchs_s));
+       memcpy(fchs, &fc_bls_rsp_tmpl, sizeof(struct fchs_s));
        fchs->d_id = d_id;
        fchs->s_id = s_id;
        fchs->ox_id = ox_id;
@@ -211,7 +211,7 @@ fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
 {
        struct fc_logi_s *plogi = (struct fc_logi_s *) (pld);
 
-       bfa_os_memcpy(plogi, &plogi_tmpl, sizeof(struct fc_logi_s));
+       memcpy(plogi, &plogi_tmpl, sizeof(struct fc_logi_s));
 
        plogi->els_cmd.els_code = els_code;
        if (els_code == FC_ELS_PLOGI)
@@ -219,10 +219,10 @@ fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
        else
                fc_els_rsp_build(fchs, d_id, s_id, ox_id);
 
-       plogi->csp.rxsz = plogi->class3.rxsz = bfa_os_htons(pdu_size);
+       plogi->csp.rxsz = plogi->class3.rxsz = cpu_to_be16(pdu_size);
 
-       bfa_os_memcpy(&plogi->port_name, &port_name, sizeof(wwn_t));
-       bfa_os_memcpy(&plogi->node_name, &node_name, sizeof(wwn_t));
+       memcpy(&plogi->port_name, &port_name, sizeof(wwn_t));
+       memcpy(&plogi->node_name, &node_name, sizeof(wwn_t));
 
        return sizeof(struct fc_logi_s);
 }
@@ -235,12 +235,12 @@ fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
        u32        d_id = bfa_os_hton3b(FC_FABRIC_PORT);
        u32     *vvl_info;
 
-       bfa_os_memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
+       memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
 
        flogi->els_cmd.els_code = FC_ELS_FLOGI;
        fc_els_req_build(fchs, d_id, s_id, ox_id);
 
-       flogi->csp.rxsz = flogi->class3.rxsz = bfa_os_htons(pdu_size);
+       flogi->csp.rxsz = flogi->class3.rxsz = cpu_to_be16(pdu_size);
        flogi->port_name = port_name;
        flogi->node_name = node_name;
 
@@ -253,14 +253,14 @@ fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
        /* set AUTH capability */
        flogi->csp.security = set_auth;
 
-       flogi->csp.bbcred = bfa_os_htons(local_bb_credits);
+       flogi->csp.bbcred = cpu_to_be16(local_bb_credits);
 
        /* Set brcd token in VVL */
        vvl_info = (u32 *)&flogi->vvl[0];
 
        /* set the flag to indicate the presence of VVL */
        flogi->csp.npiv_supp    = 1; /* @todo. field name is not correct */
-       vvl_info[0]     = bfa_os_htonl(FLOGI_VVL_BRCD);
+       vvl_info[0]     = cpu_to_be32(FLOGI_VVL_BRCD);
 
        return sizeof(struct fc_logi_s);
 }
@@ -272,15 +272,15 @@ fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
 {
        u32        d_id = 0;
 
-       bfa_os_memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
+       memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
        fc_els_rsp_build(fchs, d_id, s_id, ox_id);
 
        flogi->els_cmd.els_code = FC_ELS_ACC;
-       flogi->csp.rxsz = flogi->class3.rxsz = bfa_os_htons(pdu_size);
+       flogi->csp.rxsz = flogi->class3.rxsz = cpu_to_be16(pdu_size);
        flogi->port_name = port_name;
        flogi->node_name = node_name;
 
-       flogi->csp.bbcred = bfa_os_htons(local_bb_credits);
+       flogi->csp.bbcred = cpu_to_be16(local_bb_credits);
 
        return sizeof(struct fc_logi_s);
 }
@@ -291,12 +291,12 @@ fc_fdisc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
 {
        u32        d_id = bfa_os_hton3b(FC_FABRIC_PORT);
 
-       bfa_os_memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
+       memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
 
        flogi->els_cmd.els_code = FC_ELS_FDISC;
        fc_els_req_build(fchs, d_id, s_id, ox_id);
 
-       flogi->csp.rxsz = flogi->class3.rxsz = bfa_os_htons(pdu_size);
+       flogi->csp.rxsz = flogi->class3.rxsz = cpu_to_be16(pdu_size);
        flogi->port_name = port_name;
        flogi->node_name = node_name;
 
@@ -346,7 +346,7 @@ fc_plogi_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name)
                if (!plogi->class3.class_valid)
                        return FC_PARSE_FAILURE;
 
-               if (bfa_os_ntohs(plogi->class3.rxsz) < (FC_MIN_PDUSZ))
+               if (be16_to_cpu(plogi->class3.rxsz) < (FC_MIN_PDUSZ))
                        return FC_PARSE_FAILURE;
 
                return FC_PARSE_OK;
@@ -363,8 +363,8 @@ fc_plogi_parse(struct fchs_s *fchs)
        if (plogi->class3.class_valid != 1)
                return FC_PARSE_FAILURE;
 
-       if ((bfa_os_ntohs(plogi->class3.rxsz) < FC_MIN_PDUSZ)
-           || (bfa_os_ntohs(plogi->class3.rxsz) > FC_MAX_PDUSZ)
+       if ((be16_to_cpu(plogi->class3.rxsz) < FC_MIN_PDUSZ)
+           || (be16_to_cpu(plogi->class3.rxsz) > FC_MAX_PDUSZ)
            || (plogi->class3.rxsz == 0))
                return FC_PARSE_FAILURE;
 
@@ -378,7 +378,7 @@ fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
        struct fc_prli_s *prli = (struct fc_prli_s *) (pld);
 
        fc_els_req_build(fchs, d_id, s_id, ox_id);
-       bfa_os_memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s));
+       memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s));
 
        prli->command = FC_ELS_PRLI;
        prli->parampage.servparams.initiator     = 1;
@@ -397,7 +397,7 @@ fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
        struct fc_prli_s *prli = (struct fc_prli_s *) (pld);
 
        fc_els_rsp_build(fchs, d_id, s_id, ox_id);
-       bfa_os_memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s));
+       memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s));
 
        prli->command = FC_ELS_ACC;
 
@@ -448,7 +448,7 @@ fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, u32 d_id, u32 s_id,
 {
        fc_els_req_build(fchs, d_id, s_id, ox_id);
 
-       bfa_os_memset(logo, '\0', sizeof(struct fc_logo_s));
+       memset(logo, '\0', sizeof(struct fc_logo_s));
        logo->els_cmd.els_code = FC_ELS_LOGO;
        logo->nport_id = (s_id);
        logo->orig_port_name = port_name;
@@ -461,7 +461,7 @@ fc_adisc_x_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
                 u32 s_id, u16 ox_id, wwn_t port_name,
                 wwn_t node_name, u8 els_code)
 {
-       bfa_os_memset(adisc, '\0', sizeof(struct fc_adisc_s));
+       memset(adisc, '\0', sizeof(struct fc_adisc_s));
 
        adisc->els_cmd.els_code = els_code;
 
@@ -537,7 +537,7 @@ fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, wwn_t port_name)
        if (pdisc->class3.class_valid != 1)
                return FC_PARSE_FAILURE;
 
-       if ((bfa_os_ntohs(pdisc->class3.rxsz) <
+       if ((be16_to_cpu(pdisc->class3.rxsz) <
                (FC_MIN_PDUSZ - sizeof(struct fchs_s)))
            || (pdisc->class3.rxsz == 0))
                return FC_PARSE_FAILURE;
@@ -554,11 +554,11 @@ fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, wwn_t port_name)
 u16
 fc_abts_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id)
 {
-       bfa_os_memcpy(fchs, &fc_bls_req_tmpl, sizeof(struct fchs_s));
+       memcpy(fchs, &fc_bls_req_tmpl, sizeof(struct fchs_s));
        fchs->cat_info = FC_CAT_ABTS;
        fchs->d_id = (d_id);
        fchs->s_id = (s_id);
-       fchs->ox_id = bfa_os_htons(ox_id);
+       fchs->ox_id = cpu_to_be16(ox_id);
 
        return sizeof(struct fchs_s);
 }
@@ -582,9 +582,9 @@ fc_rrq_build(struct fchs_s *fchs, struct fc_rrq_s *rrq, u32 d_id, u32 s_id,
        /*
         * build rrq payload
         */
-       bfa_os_memcpy(rrq, &rrq_tmpl, sizeof(struct fc_rrq_s));
+       memcpy(rrq, &rrq_tmpl, sizeof(struct fc_rrq_s));
        rrq->s_id = (s_id);
-       rrq->ox_id = bfa_os_htons(rrq_oxid);
+       rrq->ox_id = cpu_to_be16(rrq_oxid);
        rrq->rx_id = FC_RXID_ANY;
 
        return sizeof(struct fc_rrq_s);
@@ -598,7 +598,7 @@ fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
 
        fc_els_rsp_build(fchs, d_id, s_id, ox_id);
 
-       bfa_os_memset(acc, 0, sizeof(struct fc_els_cmd_s));
+       memset(acc, 0, sizeof(struct fc_els_cmd_s));
        acc->els_code = FC_ELS_ACC;
 
        return sizeof(struct fc_els_cmd_s);
@@ -610,7 +610,7 @@ fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt, u32 d_id,
                u8 reason_code_expl)
 {
        fc_els_rsp_build(fchs, d_id, s_id, ox_id);
-       bfa_os_memset(ls_rjt, 0, sizeof(struct fc_ls_rjt_s));
+       memset(ls_rjt, 0, sizeof(struct fc_ls_rjt_s));
 
        ls_rjt->els_cmd.els_code = FC_ELS_LS_RJT;
        ls_rjt->reason_code = reason_code;
@@ -626,7 +626,7 @@ fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, u32 d_id,
 {
        fc_bls_rsp_build(fchs, d_id, s_id, ox_id);
 
-       bfa_os_memcpy(ba_acc, &ba_acc_tmpl, sizeof(struct fc_ba_acc_s));
+       memcpy(ba_acc, &ba_acc_tmpl, sizeof(struct fc_ba_acc_s));
 
        fchs->rx_id = rx_id;
 
@@ -641,7 +641,7 @@ fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd, u32 d_id,
                u32 s_id, u16 ox_id)
 {
        fc_els_rsp_build(fchs, d_id, s_id, ox_id);
-       bfa_os_memset(els_cmd, 0, sizeof(struct fc_els_cmd_s));
+       memset(els_cmd, 0, sizeof(struct fc_els_cmd_s));
        els_cmd->els_code = FC_ELS_ACC;
 
        return sizeof(struct fc_els_cmd_s);
@@ -656,10 +656,10 @@ fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code)
 
        if (els_code == FC_ELS_PRLO) {
                prlo = (struct fc_prlo_s *) (fc_frame + 1);
-               num_pages = (bfa_os_ntohs(prlo->payload_len) - 4) / 16;
+               num_pages = (be16_to_cpu(prlo->payload_len) - 4) / 16;
        } else {
                tprlo = (struct fc_tprlo_s *) (fc_frame + 1);
-               num_pages = (bfa_os_ntohs(tprlo->payload_len) - 4) / 16;
+               num_pages = (be16_to_cpu(tprlo->payload_len) - 4) / 16;
        }
        return num_pages;
 }
@@ -672,11 +672,11 @@ fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc,
 
        fc_els_rsp_build(fchs, d_id, s_id, ox_id);
 
-       bfa_os_memset(tprlo_acc, 0, (num_pages * 16) + 4);
+       memset(tprlo_acc, 0, (num_pages * 16) + 4);
        tprlo_acc->command = FC_ELS_ACC;
 
        tprlo_acc->page_len = 0x10;
-       tprlo_acc->payload_len = bfa_os_htons((num_pages * 16) + 4);
+       tprlo_acc->payload_len = cpu_to_be16((num_pages * 16) + 4);
 
        for (page = 0; page < num_pages; page++) {
                tprlo_acc->tprlo_acc_params[page].opa_valid = 0;
@@ -685,7 +685,7 @@ fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc,
                tprlo_acc->tprlo_acc_params[page].orig_process_assc = 0;
                tprlo_acc->tprlo_acc_params[page].resp_process_assc = 0;
        }
-       return bfa_os_ntohs(tprlo_acc->payload_len);
+       return be16_to_cpu(tprlo_acc->payload_len);
 }
 
 u16
@@ -696,10 +696,10 @@ fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, u32 d_id,
 
        fc_els_rsp_build(fchs, d_id, s_id, ox_id);
 
-       bfa_os_memset(prlo_acc, 0, (num_pages * 16) + 4);
+       memset(prlo_acc, 0, (num_pages * 16) + 4);
        prlo_acc->command = FC_ELS_ACC;
        prlo_acc->page_len = 0x10;
-       prlo_acc->payload_len = bfa_os_htons((num_pages * 16) + 4);
+       prlo_acc->payload_len = cpu_to_be16((num_pages * 16) + 4);
 
        for (page = 0; page < num_pages; page++) {
                prlo_acc->prlo_acc_params[page].opa_valid = 0;
@@ -709,7 +709,7 @@ fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, u32 d_id,
                prlo_acc->prlo_acc_params[page].resp_process_assc = 0;
        }
 
-       return bfa_os_ntohs(prlo_acc->payload_len);
+       return be16_to_cpu(prlo_acc->payload_len);
 }
 
 u16
@@ -718,7 +718,7 @@ fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, u32 d_id,
 {
        fc_els_req_build(fchs, d_id, s_id, ox_id);
 
-       bfa_os_memset(rnid, 0, sizeof(struct fc_rnid_cmd_s));
+       memset(rnid, 0, sizeof(struct fc_rnid_cmd_s));
 
        rnid->els_cmd.els_code = FC_ELS_RNID;
        rnid->node_id_data_format = data_format;
@@ -732,7 +732,7 @@ fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc, u32 d_id,
                  struct fc_rnid_common_id_data_s *common_id_data,
                  struct fc_rnid_general_topology_data_s *gen_topo_data)
 {
-       bfa_os_memset(rnid_acc, 0, sizeof(struct fc_rnid_acc_s));
+       memset(rnid_acc, 0, sizeof(struct fc_rnid_acc_s));
 
        fc_els_rsp_build(fchs, d_id, s_id, ox_id);
 
@@ -745,7 +745,7 @@ fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc, u32 d_id,
        if (data_format == RNID_NODEID_DATA_FORMAT_DISCOVERY) {
                rnid_acc->specific_id_data_length =
                        sizeof(struct fc_rnid_general_topology_data_s);
-               bfa_os_assign(rnid_acc->gen_topology_data, *gen_topo_data);
+               rnid_acc->gen_topology_data = *gen_topo_data;
                return sizeof(struct fc_rnid_acc_s);
        } else {
                return sizeof(struct fc_rnid_acc_s) -
@@ -760,7 +760,7 @@ fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc, u32 d_id,
 {
        fc_els_req_build(fchs, d_id, s_id, ox_id);
 
-       bfa_os_memset(rpsc, 0, sizeof(struct fc_rpsc_cmd_s));
+       memset(rpsc, 0, sizeof(struct fc_rpsc_cmd_s));
 
        rpsc->els_cmd.els_code = FC_ELS_RPSC;
        return sizeof(struct fc_rpsc_cmd_s);
@@ -775,11 +775,11 @@ fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rpsc2, u32 d_id,
 
        fc_els_req_build(fchs, bfa_os_hton3b(dctlr_id), s_id, 0);
 
-       bfa_os_memset(rpsc2, 0, sizeof(struct fc_rpsc2_cmd_s));
+       memset(rpsc2, 0, sizeof(struct fc_rpsc2_cmd_s));
 
        rpsc2->els_cmd.els_code = FC_ELS_RPSC;
-       rpsc2->token = bfa_os_htonl(FC_BRCD_TOKEN);
-       rpsc2->num_pids  = bfa_os_htons(npids);
+       rpsc2->token = cpu_to_be32(FC_BRCD_TOKEN);
+       rpsc2->num_pids  = cpu_to_be16(npids);
        for (i = 0; i < npids; i++)
                rpsc2->pid_list[i].pid = pid_list[i];
 
@@ -791,18 +791,18 @@ fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc,
                u32 d_id, u32 s_id, u16 ox_id,
                  struct fc_rpsc_speed_info_s *oper_speed)
 {
-       bfa_os_memset(rpsc_acc, 0, sizeof(struct fc_rpsc_acc_s));
+       memset(rpsc_acc, 0, sizeof(struct fc_rpsc_acc_s));
 
        fc_els_rsp_build(fchs, d_id, s_id, ox_id);
 
        rpsc_acc->command = FC_ELS_ACC;
-       rpsc_acc->num_entries = bfa_os_htons(1);
+       rpsc_acc->num_entries = cpu_to_be16(1);
 
        rpsc_acc->speed_info[0].port_speed_cap =
-               bfa_os_htons(oper_speed->port_speed_cap);
+               cpu_to_be16(oper_speed->port_speed_cap);
 
        rpsc_acc->speed_info[0].port_op_speed =
-               bfa_os_htons(oper_speed->port_op_speed);
+               cpu_to_be16(oper_speed->port_op_speed);
 
        return sizeof(struct fc_rpsc_acc_s);
 }
@@ -830,12 +830,12 @@ fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
 {
        struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1);
 
-       bfa_os_memcpy(pdisc, &plogi_tmpl, sizeof(struct fc_logi_s));
+       memcpy(pdisc, &plogi_tmpl, sizeof(struct fc_logi_s));
 
        pdisc->els_cmd.els_code = FC_ELS_PDISC;
        fc_els_req_build(fchs, d_id, s_id, ox_id);
 
-       pdisc->csp.rxsz = pdisc->class3.rxsz = bfa_os_htons(pdu_size);
+       pdisc->csp.rxsz = pdisc->class3.rxsz = cpu_to_be16(pdu_size);
        pdisc->port_name = port_name;
        pdisc->node_name = node_name;
 
@@ -859,7 +859,7 @@ fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name)
        if (!pdisc->class3.class_valid)
                return FC_PARSE_NWWN_NOT_EQUAL;
 
-       if (bfa_os_ntohs(pdisc->class3.rxsz) < (FC_MIN_PDUSZ))
+       if (be16_to_cpu(pdisc->class3.rxsz) < (FC_MIN_PDUSZ))
                return FC_PARSE_RXSZ_INVAL;
 
        return FC_PARSE_OK;
@@ -873,10 +873,10 @@ fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
        int             page;
 
        fc_els_req_build(fchs, d_id, s_id, ox_id);
-       bfa_os_memset(prlo, 0, (num_pages * 16) + 4);
+       memset(prlo, 0, (num_pages * 16) + 4);
        prlo->command = FC_ELS_PRLO;
        prlo->page_len = 0x10;
-       prlo->payload_len = bfa_os_htons((num_pages * 16) + 4);
+       prlo->payload_len = cpu_to_be16((num_pages * 16) + 4);
 
        for (page = 0; page < num_pages; page++) {
                prlo->prlo_params[page].type = FC_TYPE_FCP;
@@ -886,7 +886,7 @@ fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
                prlo->prlo_params[page].resp_process_assc = 0;
        }
 
-       return bfa_os_ntohs(prlo->payload_len);
+       return be16_to_cpu(prlo->payload_len);
 }
 
 u16
@@ -901,7 +901,7 @@ fc_prlo_rsp_parse(struct fchs_s *fchs, int len)
        if (prlo->command != FC_ELS_ACC)
                return FC_PARSE_FAILURE;
 
-       num_pages = ((bfa_os_ntohs(prlo->payload_len)) - 4) / 16;
+       num_pages = ((be16_to_cpu(prlo->payload_len)) - 4) / 16;
 
        for (page = 0; page < num_pages; page++) {
                if (prlo->prlo_acc_params[page].type != FC_TYPE_FCP)
@@ -931,10 +931,10 @@ fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
        int             page;
 
        fc_els_req_build(fchs, d_id, s_id, ox_id);
-       bfa_os_memset(tprlo, 0, (num_pages * 16) + 4);
+       memset(tprlo, 0, (num_pages * 16) + 4);
        tprlo->command = FC_ELS_TPRLO;
        tprlo->page_len = 0x10;
-       tprlo->payload_len = bfa_os_htons((num_pages * 16) + 4);
+       tprlo->payload_len = cpu_to_be16((num_pages * 16) + 4);
 
        for (page = 0; page < num_pages; page++) {
                tprlo->tprlo_params[page].type = FC_TYPE_FCP;
@@ -950,7 +950,7 @@ fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
                }
        }
 
-       return bfa_os_ntohs(tprlo->payload_len);
+       return be16_to_cpu(tprlo->payload_len);
 }
 
 u16
@@ -965,7 +965,7 @@ fc_tprlo_rsp_parse(struct fchs_s *fchs, int len)
        if (tprlo->command != FC_ELS_ACC)
                return FC_PARSE_ACC_INVAL;
 
-       num_pages = (bfa_os_ntohs(tprlo->payload_len) - 4) / 16;
+       num_pages = (be16_to_cpu(tprlo->payload_len) - 4) / 16;
 
        for (page = 0; page < num_pages; page++) {
                if (tprlo->tprlo_acc_params[page].type != FC_TYPE_FCP)
@@ -1011,32 +1011,32 @@ fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
 static void
 fc_gs_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code)
 {
-       bfa_os_memset(cthdr, 0, sizeof(struct ct_hdr_s));
+       memset(cthdr, 0, sizeof(struct ct_hdr_s));
        cthdr->rev_id = CT_GS3_REVISION;
        cthdr->gs_type = CT_GSTYPE_DIRSERVICE;
        cthdr->gs_sub_type = CT_GSSUBTYPE_NAMESERVER;
-       cthdr->cmd_rsp_code = bfa_os_htons(cmd_code);
+       cthdr->cmd_rsp_code = cpu_to_be16(cmd_code);
 }
 
 static void
 fc_gs_fdmi_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code)
 {
-       bfa_os_memset(cthdr, 0, sizeof(struct ct_hdr_s));
+       memset(cthdr, 0, sizeof(struct ct_hdr_s));
        cthdr->rev_id = CT_GS3_REVISION;
        cthdr->gs_type = CT_GSTYPE_MGMTSERVICE;
        cthdr->gs_sub_type = CT_GSSUBTYPE_HBA_MGMTSERVER;
-       cthdr->cmd_rsp_code = bfa_os_htons(cmd_code);
+       cthdr->cmd_rsp_code = cpu_to_be16(cmd_code);
 }
 
 static void
 fc_gs_ms_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code,
                                         u8 sub_type)
 {
-       bfa_os_memset(cthdr, 0, sizeof(struct ct_hdr_s));
+       memset(cthdr, 0, sizeof(struct ct_hdr_s));
        cthdr->rev_id = CT_GS3_REVISION;
        cthdr->gs_type = CT_GSTYPE_MGMTSERVICE;
        cthdr->gs_sub_type = sub_type;
-       cthdr->cmd_rsp_code = bfa_os_htons(cmd_code);
+       cthdr->cmd_rsp_code = cpu_to_be16(cmd_code);
 }
 
 u16
@@ -1050,7 +1050,7 @@ fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
        fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
        fc_gs_cthdr_build(cthdr, s_id, GS_GID_PN);
 
-       bfa_os_memset(gidpn, 0, sizeof(struct fcgs_gidpn_req_s));
+       memset(gidpn, 0, sizeof(struct fcgs_gidpn_req_s));
        gidpn->port_name = port_name;
        return sizeof(struct fcgs_gidpn_req_s) + sizeof(struct ct_hdr_s);
 }
@@ -1066,7 +1066,7 @@ fc_gpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
        fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
        fc_gs_cthdr_build(cthdr, s_id, GS_GPN_ID);
 
-       bfa_os_memset(gpnid, 0, sizeof(fcgs_gpnid_req_t));
+       memset(gpnid, 0, sizeof(fcgs_gpnid_req_t));
        gpnid->dap = port_id;
        return sizeof(fcgs_gpnid_req_t) + sizeof(struct ct_hdr_s);
 }
@@ -1082,7 +1082,7 @@ fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
        fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
        fc_gs_cthdr_build(cthdr, s_id, GS_GNN_ID);
 
-       bfa_os_memset(gnnid, 0, sizeof(fcgs_gnnid_req_t));
+       memset(gnnid, 0, sizeof(fcgs_gnnid_req_t));
        gnnid->dap = port_id;
        return sizeof(fcgs_gnnid_req_t) + sizeof(struct ct_hdr_s);
 }
@@ -1090,7 +1090,7 @@ fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
 u16
 fc_ct_rsp_parse(struct ct_hdr_s *cthdr)
 {
-       if (bfa_os_ntohs(cthdr->cmd_rsp_code) != CT_RSP_ACCEPT) {
+       if (be16_to_cpu(cthdr->cmd_rsp_code) != CT_RSP_ACCEPT) {
                if (cthdr->reason_code == CT_RSN_LOGICAL_BUSY)
                        return FC_PARSE_BUSY;
                else
@@ -1108,7 +1108,7 @@ fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr,
 
        fc_els_req_build(fchs, d_id, s_id, ox_id);
 
-       bfa_os_memset(scr, 0, sizeof(struct fc_scr_s));
+       memset(scr, 0, sizeof(struct fc_scr_s));
        scr->command = FC_ELS_SCR;
        scr->reg_func = FC_SCR_REG_FUNC_FULL;
        if (set_br_reg)
@@ -1129,7 +1129,7 @@ fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn,
        rscn->pagelen = sizeof(rscn->event[0]);
 
        payldlen = sizeof(u32) + rscn->pagelen;
-       rscn->payldlen = bfa_os_htons(payldlen);
+       rscn->payldlen = cpu_to_be16(payldlen);
 
        rscn->event[0].format = FC_RSCN_FORMAT_PORTID;
        rscn->event[0].portid = s_id;
@@ -1149,14 +1149,14 @@ fc_rftid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
        fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
        fc_gs_cthdr_build(cthdr, s_id, GS_RFT_ID);
 
-       bfa_os_memset(rftid, 0, sizeof(struct fcgs_rftid_req_s));
+       memset(rftid, 0, sizeof(struct fcgs_rftid_req_s));
 
        rftid->dap = s_id;
 
        /* By default, FCP FC4 Type is registered */
        index = FC_TYPE_FCP >> 5;
        type_value = 1 << (FC_TYPE_FCP % 32);
-       rftid->fc4_type[index] = bfa_os_htonl(type_value);
+       rftid->fc4_type[index] = cpu_to_be32(type_value);
 
        return sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s);
 }
@@ -1172,10 +1172,10 @@ fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
        fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
        fc_gs_cthdr_build(cthdr, s_id, GS_RFT_ID);
 
-       bfa_os_memset(rftid, 0, sizeof(struct fcgs_rftid_req_s));
+       memset(rftid, 0, sizeof(struct fcgs_rftid_req_s));
 
        rftid->dap = s_id;
-       bfa_os_memcpy((void *)rftid->fc4_type, (void *)fc4_bitmap,
+       memcpy((void *)rftid->fc4_type, (void *)fc4_bitmap,
                (bitmap_size < 32 ? bitmap_size : 32));
 
        return sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s);
@@ -1192,7 +1192,7 @@ fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
        fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
        fc_gs_cthdr_build(cthdr, s_id, GS_RFF_ID);
 
-       bfa_os_memset(rffid, 0, sizeof(struct fcgs_rffid_req_s));
+       memset(rffid, 0, sizeof(struct fcgs_rffid_req_s));
 
        rffid->dap          = s_id;
        rffid->fc4ftr_bits  = fc4_ftrs;
@@ -1214,7 +1214,7 @@ fc_rspnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
        fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
        fc_gs_cthdr_build(cthdr, s_id, GS_RSPN_ID);
 
-       bfa_os_memset(rspnid, 0, sizeof(struct fcgs_rspnid_req_s));
+       memset(rspnid, 0, sizeof(struct fcgs_rspnid_req_s));
 
        rspnid->dap = s_id;
        rspnid->spn_len = (u8) strlen((char *)name);
@@ -1235,7 +1235,7 @@ fc_gid_ft_build(struct fchs_s *fchs, void *pyld, u32 s_id, u8 fc4_type)
 
        fc_gs_cthdr_build(cthdr, s_id, GS_GID_FT);
 
-       bfa_os_memset(gidft, 0, sizeof(struct fcgs_gidft_req_s));
+       memset(gidft, 0, sizeof(struct fcgs_gidft_req_s));
        gidft->fc4_type = fc4_type;
        gidft->domain_id = 0;
        gidft->area_id = 0;
@@ -1254,7 +1254,7 @@ fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
        fc_gs_fchdr_build(fchs, d_id, s_id, 0);
        fc_gs_cthdr_build(cthdr, s_id, GS_RPN_ID);
 
-       bfa_os_memset(rpnid, 0, sizeof(struct fcgs_rpnid_req_s));
+       memset(rpnid, 0, sizeof(struct fcgs_rpnid_req_s));
        rpnid->port_id = port_id;
        rpnid->port_name = port_name;
 
@@ -1272,7 +1272,7 @@ fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
        fc_gs_fchdr_build(fchs, d_id, s_id, 0);
        fc_gs_cthdr_build(cthdr, s_id, GS_RNN_ID);
 
-       bfa_os_memset(rnnid, 0, sizeof(struct fcgs_rnnid_req_s));
+       memset(rnnid, 0, sizeof(struct fcgs_rnnid_req_s));
        rnnid->port_id = port_id;
        rnnid->node_name = node_name;
 
@@ -1291,7 +1291,7 @@ fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
        fc_gs_fchdr_build(fchs, d_id, s_id, 0);
        fc_gs_cthdr_build(cthdr, s_id, GS_RCS_ID);
 
-       bfa_os_memset(rcsid, 0, sizeof(struct fcgs_rcsid_req_s));
+       memset(rcsid, 0, sizeof(struct fcgs_rcsid_req_s));
        rcsid->port_id = port_id;
        rcsid->cos = cos;
 
@@ -1309,7 +1309,7 @@ fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
        fc_gs_fchdr_build(fchs, d_id, s_id, 0);
        fc_gs_cthdr_build(cthdr, s_id, GS_RPT_ID);
 
-       bfa_os_memset(rptid, 0, sizeof(struct fcgs_rptid_req_s));
+       memset(rptid, 0, sizeof(struct fcgs_rptid_req_s));
        rptid->port_id = port_id;
        rptid->port_type = port_type;
 
@@ -1326,7 +1326,7 @@ fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id)
        fc_gs_fchdr_build(fchs, d_id, s_id, 0);
        fc_gs_cthdr_build(cthdr, s_id, GS_GA_NXT);
 
-       bfa_os_memset(ganxt, 0, sizeof(struct fcgs_ganxt_req_s));
+       memset(ganxt, 0, sizeof(struct fcgs_ganxt_req_s));
        ganxt->port_id = port_id;
 
        return sizeof(struct ct_hdr_s) + sizeof(struct fcgs_ganxt_req_s);
@@ -1365,7 +1365,7 @@ fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask)
 
        index = fc4_type >> 5;
        type_value = 1 << (fc4_type % 32);
-       ptr[index] = bfa_os_htonl(type_value);
+       ptr[index] = cpu_to_be32(type_value);
 
 }
 
@@ -1383,7 +1383,7 @@ fc_gmal_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn)
        fc_gs_ms_cthdr_build(cthdr, s_id, GS_FC_GMAL_CMD,
                        CT_GSSUBTYPE_CFGSERVER);
 
-       bfa_os_memset(gmal, 0, sizeof(fcgs_gmal_req_t));
+       memset(gmal, 0, sizeof(fcgs_gmal_req_t));
        gmal->wwn = wwn;
 
        return sizeof(struct ct_hdr_s) + sizeof(fcgs_gmal_req_t);
@@ -1403,7 +1403,7 @@ fc_gfn_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn)
        fc_gs_ms_cthdr_build(cthdr, s_id, GS_FC_GFN_CMD,
                        CT_GSSUBTYPE_CFGSERVER);
 
-       bfa_os_memset(gfn, 0, sizeof(fcgs_gfn_req_t));
+       memset(gfn, 0, sizeof(fcgs_gfn_req_t));
        gfn->wwn = wwn;
 
        return sizeof(struct ct_hdr_s) + sizeof(fcgs_gfn_req_t);
index 33c8dd51f4748677fadc78b518fc51964a318859..135c4427801cf66abc97719c6e9fe78ea6a9a8d1 100644 (file)
@@ -26,7 +26,7 @@ BFA_MODULE(fcpim);
        (__l->__stats += __r->__stats)
 
 
-/**
+/*
  *  BFA ITNIM Related definitions
  */
 static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim);
@@ -72,7 +72,7 @@ static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim);
        }                                                               \
 } while (0)
 
-/**
+/*
  *  bfa_itnim_sm BFA itnim state machine
  */
 
@@ -89,7 +89,7 @@ enum bfa_itnim_event {
        BFA_ITNIM_SM_QRESUME = 9,       /*  queue space available */
 };
 
-/**
+/*
  *  BFA IOIM related definitions
  */
 #define bfa_ioim_move_to_comp_q(__ioim) do {                           \
@@ -107,11 +107,11 @@ enum bfa_itnim_event {
        if ((__fcpim)->profile_start)                                   \
                (__fcpim)->profile_start(__ioim);                       \
 } while (0)
-/**
+/*
  *  hal_ioim_sm
  */
 
-/**
+/*
  * IO state machine events
  */
 enum bfa_ioim_event {
@@ -136,11 +136,11 @@ enum bfa_ioim_event {
 };
 
 
-/**
+/*
  *  BFA TSKIM related definitions
  */
 
-/**
+/*
  * task management completion handling
  */
 #define bfa_tskim_qcomp(__tskim, __cbfn) do {                          \
@@ -165,7 +165,7 @@ enum bfa_tskim_event {
        BFA_TSKIM_SM_CLEANUP_DONE = 9,  /*  TM abort completion */
 };
 
-/**
+/*
  * forward declaration for BFA ITNIM functions
  */
 static void     bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim);
@@ -183,7 +183,7 @@ static void     bfa_itnim_iotov_start(struct bfa_itnim_s *itnim);
 static void     bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim);
 static void     bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim);
 
-/**
+/*
  * forward declaration of ITNIM state machine
  */
 static void     bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim,
@@ -217,7 +217,7 @@ static void     bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim,
 static void     bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim,
                                        enum bfa_itnim_event event);
 
-/**
+/*
  * forward declaration for BFA IOIM functions
  */
 static bfa_boolean_t   bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim);
@@ -233,7 +233,7 @@ static void __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete);
 static bfa_boolean_t    bfa_ioim_is_abortable(struct bfa_ioim_s *ioim);
 
 
-/**
+/*
  * forward declaration of BFA IO state machine
  */
 static void     bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim,
@@ -261,7 +261,7 @@ static void     bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim,
 static void    bfa_ioim_sm_cmnd_retry(struct bfa_ioim_s *ioim,
                                        enum bfa_ioim_event event);
 
-/**
+/*
  * forward declaration for BFA TSKIM functions
  */
 static void     __bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete);
@@ -276,7 +276,7 @@ static bfa_boolean_t bfa_tskim_send_abort(struct bfa_tskim_s *tskim);
 static void     bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim);
 
 
-/**
+/*
  * forward declaration of BFA TSKIM state machine
  */
 static void     bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim,
@@ -294,11 +294,11 @@ static void     bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
 static void     bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim,
                                        enum bfa_tskim_event event);
 
-/**
+/*
  *  hal_fcpim_mod BFA FCP Initiator Mode module
  */
 
-/**
+/*
  *     Compute and return memory needed by FCP(im) module.
  */
 static void
@@ -307,7 +307,7 @@ bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
 {
        bfa_itnim_meminfo(cfg, km_len, dm_len);
 
-       /**
+       /*
         * IO memory
         */
        if (cfg->fwcfg.num_ioim_reqs < BFA_IOIM_MIN)
@@ -320,7 +320,7 @@ bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
 
        *dm_len += cfg->fwcfg.num_ioim_reqs * BFI_IOIM_SNSLEN;
 
-       /**
+       /*
         * task management command memory
         */
        if (cfg->fwcfg.num_tskim_reqs < BFA_TSKIM_MIN)
@@ -463,7 +463,7 @@ bfa_fcpim_port_iostats(struct bfa_s *bfa, struct bfa_itnim_iostats_s *stats,
        struct bfa_itnim_s *itnim;
 
        /* accumulate IO stats from itnim */
-       bfa_os_memset(stats, 0, sizeof(struct bfa_itnim_iostats_s));
+       memset(stats, 0, sizeof(struct bfa_itnim_iostats_s));
        list_for_each_safe(qe, qen, &fcpim->itnim_q) {
                itnim = (struct bfa_itnim_s *) qe;
                if (itnim->rport->rport_info.lp_tag != lp_tag)
@@ -480,7 +480,7 @@ bfa_fcpim_get_modstats(struct bfa_s *bfa, struct bfa_itnim_iostats_s *modstats)
        struct bfa_itnim_s *itnim;
 
        /* accumulate IO stats from itnim */
-       bfa_os_memset(modstats, 0, sizeof(struct bfa_itnim_iostats_s));
+       memset(modstats, 0, sizeof(struct bfa_itnim_iostats_s));
        list_for_each_safe(qe, qen, &fcpim->itnim_q) {
                itnim = (struct bfa_itnim_s *) qe;
                bfa_fcpim_add_stats(modstats, &(itnim->stats));
@@ -560,7 +560,7 @@ bfa_fcpim_clr_modstats(struct bfa_s *bfa)
                itnim = (struct bfa_itnim_s *) qe;
                bfa_itnim_clear_stats(itnim);
        }
-       bfa_os_memset(&fcpim->del_itn_stats, 0,
+       memset(&fcpim->del_itn_stats, 0,
                sizeof(struct bfa_fcpim_del_itn_stats_s));
 
        return BFA_STATUS_OK;
@@ -604,11 +604,11 @@ bfa_fcpim_set_ioredirect(struct bfa_s *bfa, bfa_boolean_t state)
 
 
 
-/**
+/*
  *  BFA ITNIM module state machine functions
  */
 
-/**
+/*
  *     Beginning/unallocated state - no events expected.
  */
 static void
@@ -629,7 +629,7 @@ bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
        }
 }
 
-/**
+/*
  *     Beginning state, only online event expected.
  */
 static void
@@ -660,7 +660,7 @@ bfa_itnim_sm_created(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
        }
 }
 
-/**
+/*
  *     Waiting for itnim create response from firmware.
  */
 static void
@@ -732,7 +732,7 @@ bfa_itnim_sm_fwcreate_qfull(struct bfa_itnim_s *itnim,
        }
 }
 
-/**
+/*
  *     Waiting for itnim create response from firmware, a delete is pending.
  */
 static void
@@ -760,7 +760,7 @@ bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim,
        }
 }
 
-/**
+/*
  *     Online state - normal parking state.
  */
 static void
@@ -802,7 +802,7 @@ bfa_itnim_sm_online(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
        }
 }
 
-/**
+/*
  *     Second level error recovery need.
  */
 static void
@@ -833,7 +833,7 @@ bfa_itnim_sm_sler(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
        }
 }
 
-/**
+/*
  *     Going offline. Waiting for active IO cleanup.
  */
 static void
@@ -870,7 +870,7 @@ bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim,
        }
 }
 
-/**
+/*
  *     Deleting itnim. Waiting for active IO cleanup.
  */
 static void
@@ -898,7 +898,7 @@ bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim,
        }
 }
 
-/**
+/*
  * Rport offline. Fimrware itnim is being deleted - awaiting f/w response.
  */
 static void
@@ -955,7 +955,7 @@ bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim,
        }
 }
 
-/**
+/*
  *     Offline state.
  */
 static void
@@ -987,7 +987,7 @@ bfa_itnim_sm_offline(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
        }
 }
 
-/**
+/*
  *     IOC h/w failed state.
  */
 static void
@@ -1023,7 +1023,7 @@ bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim,
        }
 }
 
-/**
+/*
  *     Itnim is deleted, waiting for firmware response to delete.
  */
 static void
@@ -1068,7 +1068,7 @@ bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim,
        }
 }
 
-/**
+/*
  *     Initiate cleanup of all IOs on an IOC failure.
  */
 static void
@@ -1088,7 +1088,7 @@ bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim)
                bfa_ioim_iocdisable(ioim);
        }
 
-       /**
+       /*
         * For IO request in pending queue, we pretend an early timeout.
         */
        list_for_each_safe(qe, qen, &itnim->pending_q) {
@@ -1102,7 +1102,7 @@ bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim)
        }
 }
 
-/**
+/*
  *     IO cleanup completion
  */
 static void
@@ -1114,7 +1114,7 @@ bfa_itnim_cleanp_comp(void *itnim_cbarg)
        bfa_sm_send_event(itnim, BFA_ITNIM_SM_CLEANUP);
 }
 
-/**
+/*
  *     Initiate cleanup of all IOs.
  */
 static void
@@ -1129,7 +1129,7 @@ bfa_itnim_cleanup(struct bfa_itnim_s *itnim)
        list_for_each_safe(qe, qen, &itnim->io_q) {
                ioim = (struct bfa_ioim_s *) qe;
 
-               /**
+               /*
                 * Move IO to a cleanup queue from active queue so that a later
                 * TM will not pickup this IO.
                 */
@@ -1176,7 +1176,7 @@ __bfa_cb_itnim_sler(void *cbarg, bfa_boolean_t complete)
                bfa_cb_itnim_sler(itnim->ditn);
 }
 
-/**
+/*
  * Call to resume any I/O requests waiting for room in request queue.
  */
 static void
@@ -1190,7 +1190,7 @@ bfa_itnim_qresume(void *cbarg)
 
 
 
-/**
+/*
  *  bfa_itnim_public
  */
 
@@ -1210,7 +1210,7 @@ void
 bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
                u32 *dm_len)
 {
-       /**
+       /*
         * ITN memory
         */
        *km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_itnim_s);
@@ -1229,7 +1229,7 @@ bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
        fcpim->itnim_arr = itnim;
 
        for (i = 0; i < fcpim->num_itnims; i++, itnim++) {
-               bfa_os_memset(itnim, 0, sizeof(struct bfa_itnim_s));
+               memset(itnim, 0, sizeof(struct bfa_itnim_s));
                itnim->bfa = bfa;
                itnim->fcpim = fcpim;
                itnim->reqq = BFA_REQQ_QOS_LO;
@@ -1264,7 +1264,7 @@ bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim)
 
        itnim->msg_no++;
 
-       /**
+       /*
         * check for room in queue to send request now
         */
        m = bfa_reqq_next(itnim->bfa, itnim->reqq);
@@ -1281,7 +1281,7 @@ bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim)
        m->msg_no = itnim->msg_no;
        bfa_stats(itnim, fw_create);
 
-       /**
+       /*
         * queue I/O message to firmware
         */
        bfa_reqq_produce(itnim->bfa, itnim->reqq);
@@ -1293,7 +1293,7 @@ bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim)
 {
        struct bfi_itnim_delete_req_s *m;
 
-       /**
+       /*
         * check for room in queue to send request now
         */
        m = bfa_reqq_next(itnim->bfa, itnim->reqq);
@@ -1307,14 +1307,14 @@ bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim)
        m->fw_handle = itnim->rport->fw_handle;
        bfa_stats(itnim, fw_delete);
 
-       /**
+       /*
         * queue I/O message to firmware
         */
        bfa_reqq_produce(itnim->bfa, itnim->reqq);
        return BFA_TRUE;
 }
 
-/**
+/*
  * Cleanup all pending failed inflight requests.
  */
 static void
@@ -1329,7 +1329,7 @@ bfa_itnim_delayed_comp(struct bfa_itnim_s *itnim, bfa_boolean_t iotov)
        }
 }
 
-/**
+/*
  * Start all pending IO requests.
  */
 static void
@@ -1339,12 +1339,12 @@ bfa_itnim_iotov_online(struct bfa_itnim_s *itnim)
 
        bfa_itnim_iotov_stop(itnim);
 
-       /**
+       /*
         * Abort all inflight IO requests in the queue
         */
        bfa_itnim_delayed_comp(itnim, BFA_FALSE);
 
-       /**
+       /*
         * Start all pending IO requests.
         */
        while (!list_empty(&itnim->pending_q)) {
@@ -1354,7 +1354,7 @@ bfa_itnim_iotov_online(struct bfa_itnim_s *itnim)
        }
 }
 
-/**
+/*
  * Fail all pending IO requests
  */
 static void
@@ -1362,12 +1362,12 @@ bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim)
 {
        struct bfa_ioim_s *ioim;
 
-       /**
+       /*
         * Fail all inflight IO requests in the queue
         */
        bfa_itnim_delayed_comp(itnim, BFA_TRUE);
 
-       /**
+       /*
         * Fail any pending IO requests.
         */
        while (!list_empty(&itnim->pending_q)) {
@@ -1377,7 +1377,7 @@ bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim)
        }
 }
 
-/**
+/*
  * IO TOV timer callback. Fail any pending IO requests.
  */
 static void
@@ -1392,7 +1392,7 @@ bfa_itnim_iotov(void *itnim_arg)
        bfa_cb_itnim_tov(itnim->ditn);
 }
 
-/**
+/*
  * Start IO TOV timer for failing back pending IO requests in offline state.
  */
 static void
@@ -1407,7 +1407,7 @@ bfa_itnim_iotov_start(struct bfa_itnim_s *itnim)
        }
 }
 
-/**
+/*
  * Stop IO TOV timer.
  */
 static void
@@ -1419,7 +1419,7 @@ bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim)
        }
 }
 
-/**
+/*
  * Stop IO TOV timer.
  */
 static void
@@ -1459,11 +1459,11 @@ bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim)
 
 
 
-/**
+/*
  *  bfa_itnim_public
  */
 
-/**
+/*
  *     Itnim interrupt processing.
  */
 void
@@ -1509,7 +1509,7 @@ bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
 
 
 
-/**
+/*
  *  bfa_itnim_api
  */
 
@@ -1552,7 +1552,7 @@ bfa_itnim_offline(struct bfa_itnim_s *itnim)
        bfa_sm_send_event(itnim, BFA_ITNIM_SM_OFFLINE);
 }
 
-/**
+/*
  * Return true if itnim is considered offline for holding off IO request.
  * IO is not held if itnim is being deleted.
  */
@@ -1597,17 +1597,17 @@ void
 bfa_itnim_clear_stats(struct bfa_itnim_s *itnim)
 {
        int j;
-       bfa_os_memset(&itnim->stats, 0, sizeof(itnim->stats));
-       bfa_os_memset(&itnim->ioprofile, 0, sizeof(itnim->ioprofile));
+       memset(&itnim->stats, 0, sizeof(itnim->stats));
+       memset(&itnim->ioprofile, 0, sizeof(itnim->ioprofile));
        for (j = 0; j < BFA_IOBUCKET_MAX; j++)
                itnim->ioprofile.io_latency.min[j] = ~0;
 }
 
-/**
+/*
  *  BFA IO module state machine functions
  */
 
-/**
+/*
  *     IO is not started (unallocated).
  */
 static void
@@ -1657,7 +1657,7 @@ bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                break;
 
        case BFA_IOIM_SM_ABORT:
-               /**
+               /*
                 * IO in pending queue can get abort requests. Complete abort
                 * requests immediately.
                 */
@@ -1672,7 +1672,7 @@ bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
        }
 }
 
-/**
+/*
  *     IO is waiting for SG pages.
  */
 static void
@@ -1719,7 +1719,7 @@ bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
        }
 }
 
-/**
+/*
  *     IO is active.
  */
 static void
@@ -1803,7 +1803,7 @@ bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
        }
 }
 
-/**
+/*
 *      IO is retried with new tag.
 */
 static void
@@ -1844,7 +1844,7 @@ bfa_ioim_sm_cmnd_retry(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                break;
 
        case BFA_IOIM_SM_ABORT:
-               /** in this state IO abort is done.
+               /* in this state IO abort is done.
                 * Waiting for IO tag resource free.
                 */
                bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
@@ -1857,7 +1857,7 @@ bfa_ioim_sm_cmnd_retry(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
        }
 }
 
-/**
+/*
  *     IO is being aborted, waiting for completion from firmware.
  */
 static void
@@ -1919,7 +1919,7 @@ bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
        }
 }
 
-/**
+/*
  * IO is being cleaned up (implicit abort), waiting for completion from
  * firmware.
  */
@@ -1937,7 +1937,7 @@ bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                break;
 
        case BFA_IOIM_SM_ABORT:
-               /**
+               /*
                 * IO is already being aborted implicitly
                 */
                ioim->io_cbfn = __bfa_cb_ioim_abort;
@@ -1969,7 +1969,7 @@ bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                break;
 
        case BFA_IOIM_SM_CLEANUP:
-               /**
+               /*
                 * IO can be in cleanup state already due to TM command.
                 * 2nd cleanup request comes from ITN offline event.
                 */
@@ -1980,7 +1980,7 @@ bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
        }
 }
 
-/**
+/*
  *     IO is waiting for room in request CQ
  */
 static void
@@ -2024,7 +2024,7 @@ bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
        }
 }
 
-/**
+/*
  *     Active IO is being aborted, waiting for room in request CQ.
  */
 static void
@@ -2075,7 +2075,7 @@ bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
        }
 }
 
-/**
+/*
  *     Active IO is being cleaned up, waiting for room in request CQ.
  */
 static void
@@ -2091,7 +2091,7 @@ bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                break;
 
        case BFA_IOIM_SM_ABORT:
-               /**
+               /*
                 * IO is alraedy being cleaned up implicitly
                 */
                ioim->io_cbfn = __bfa_cb_ioim_abort;
@@ -2125,7 +2125,7 @@ bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
        }
 }
 
-/**
+/*
  * IO bfa callback is pending.
  */
 static void
@@ -2152,7 +2152,7 @@ bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
        }
 }
 
-/**
+/*
  * IO bfa callback is pending. IO resource cannot be freed.
  */
 static void
@@ -2185,7 +2185,7 @@ bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
        }
 }
 
-/**
+/*
  * IO is completed, waiting resource free from firmware.
  */
 static void
@@ -2214,7 +2214,7 @@ bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
 
 
 
-/**
+/*
  *  hal_ioim_private
  */
 
@@ -2247,7 +2247,7 @@ __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete)
 
        m = (struct bfi_ioim_rsp_s *) &ioim->iosp->comp_rspmsg;
        if (m->io_status == BFI_IOIM_STS_OK) {
-               /**
+               /*
                 * setup sense information, if present
                 */
                if ((m->scsi_status == SCSI_STATUS_CHECK_CONDITION) &&
@@ -2256,15 +2256,15 @@ __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete)
                        snsinfo = ioim->iosp->snsinfo;
                }
 
-               /**
+               /*
                 * setup residue value correctly for normal completions
                 */
                if (m->resid_flags == FCP_RESID_UNDER) {
-                       residue = bfa_os_ntohl(m->residue);
+                       residue = be32_to_cpu(m->residue);
                        bfa_stats(ioim->itnim, iocomp_underrun);
                }
                if (m->resid_flags == FCP_RESID_OVER) {
-                       residue = bfa_os_ntohl(m->residue);
+                       residue = be32_to_cpu(m->residue);
                        residue = -residue;
                        bfa_stats(ioim->itnim, iocomp_overrun);
                }
@@ -2327,7 +2327,7 @@ bfa_ioim_sgpg_alloced(void *cbarg)
        bfa_sm_send_event(ioim, BFA_IOIM_SM_SGALLOCED);
 }
 
-/**
+/*
  * Send I/O request to firmware.
  */
 static bfa_boolean_t
@@ -2343,7 +2343,7 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
        struct scatterlist *sg;
        struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio;
 
-       /**
+       /*
         * check for room in queue to send request now
         */
        m = bfa_reqq_next(ioim->bfa, ioim->reqq);
@@ -2354,14 +2354,14 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
                return BFA_FALSE;
        }
 
-       /**
+       /*
         * build i/o request message next
         */
-       m->io_tag = bfa_os_htons(ioim->iotag);
+       m->io_tag = cpu_to_be16(ioim->iotag);
        m->rport_hdl = ioim->itnim->rport->fw_handle;
        m->io_timeout = bfa_cb_ioim_get_timeout(ioim->dio);
 
-       /**
+       /*
         * build inline IO SG element here
         */
        sge = &m->sges[0];
@@ -2387,18 +2387,17 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
        sge->flags = BFI_SGE_PGDLEN;
        bfa_sge_to_be(sge);
 
-       /**
+       /*
         * set up I/O command parameters
         */
-       bfa_os_assign(m->cmnd, cmnd_z0);
+       m->cmnd = cmnd_z0;
        m->cmnd.lun = bfa_cb_ioim_get_lun(ioim->dio);
        m->cmnd.iodir = bfa_cb_ioim_get_iodir(ioim->dio);
-       bfa_os_assign(m->cmnd.cdb,
-                       *(scsi_cdb_t *)bfa_cb_ioim_get_cdb(ioim->dio));
+       m->cmnd.cdb = *(scsi_cdb_t *)bfa_cb_ioim_get_cdb(ioim->dio);
        fcp_dl = bfa_cb_ioim_get_size(ioim->dio);
-       m->cmnd.fcp_dl = bfa_os_htonl(fcp_dl);
+       m->cmnd.fcp_dl = cpu_to_be32(fcp_dl);
 
-       /**
+       /*
         * set up I/O message header
         */
        switch (m->cmnd.iodir) {
@@ -2427,28 +2426,28 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
        m->cmnd.priority = bfa_cb_ioim_get_priority(ioim->dio);
        m->cmnd.taskattr = bfa_cb_ioim_get_taskattr(ioim->dio);
 
-       /**
+       /*
         * Handle large CDB (>16 bytes).
         */
        m->cmnd.addl_cdb_len = (bfa_cb_ioim_get_cdblen(ioim->dio) -
                                        FCP_CMND_CDB_LEN) / sizeof(u32);
        if (m->cmnd.addl_cdb_len) {
-               bfa_os_memcpy(&m->cmnd.cdb + 1, (scsi_cdb_t *)
+               memcpy(&m->cmnd.cdb + 1, (scsi_cdb_t *)
                                bfa_cb_ioim_get_cdb(ioim->dio) + 1,
                                m->cmnd.addl_cdb_len * sizeof(u32));
                fcp_cmnd_fcpdl(&m->cmnd) =
-                               bfa_os_htonl(bfa_cb_ioim_get_size(ioim->dio));
+                               cpu_to_be32(bfa_cb_ioim_get_size(ioim->dio));
        }
 #endif
 
-       /**
+       /*
         * queue I/O message to firmware
         */
        bfa_reqq_produce(ioim->bfa, ioim->reqq);
        return BFA_TRUE;
 }
 
-/**
+/*
  * Setup any additional SG pages needed.Inline SG element is setup
  * at queuing time.
  */
@@ -2459,7 +2458,7 @@ bfa_ioim_sge_setup(struct bfa_ioim_s *ioim)
 
        bfa_assert(ioim->nsges > BFI_SGE_INLINE);
 
-       /**
+       /*
         * allocate SG pages needed
         */
        nsgpgs = BFA_SGPG_NPAGE(ioim->nsges);
@@ -2508,7 +2507,7 @@ bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)
                        sge->sg_len = sg_dma_len(sg);
                        pgcumsz += sge->sg_len;
 
-                       /**
+                       /*
                         * set flags
                         */
                        if (i < (nsges - 1))
@@ -2523,7 +2522,7 @@ bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)
 
                sgpg = (struct bfa_sgpg_s *) bfa_q_next(sgpg);
 
-               /**
+               /*
                 * set the link element of each page
                 */
                if (sgeid == ioim->nsges) {
@@ -2540,7 +2539,7 @@ bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)
        } while (sgeid < ioim->nsges);
 }
 
-/**
+/*
  * Send I/O abort request to firmware.
  */
 static bfa_boolean_t
@@ -2549,14 +2548,14 @@ bfa_ioim_send_abort(struct bfa_ioim_s *ioim)
        struct bfi_ioim_abort_req_s *m;
        enum bfi_ioim_h2i       msgop;
 
-       /**
+       /*
         * check for room in queue to send request now
         */
        m = bfa_reqq_next(ioim->bfa, ioim->reqq);
        if (!m)
                return BFA_FALSE;
 
-       /**
+       /*
         * build i/o request message next
         */
        if (ioim->iosp->abort_explicit)
@@ -2565,17 +2564,17 @@ bfa_ioim_send_abort(struct bfa_ioim_s *ioim)
                msgop = BFI_IOIM_H2I_IOCLEANUP_REQ;
 
        bfi_h2i_set(m->mh, BFI_MC_IOIM, msgop, bfa_lpuid(ioim->bfa));
-       m->io_tag    = bfa_os_htons(ioim->iotag);
+       m->io_tag    = cpu_to_be16(ioim->iotag);
        m->abort_tag = ++ioim->abort_tag;
 
-       /**
+       /*
         * queue I/O message to firmware
         */
        bfa_reqq_produce(ioim->bfa, ioim->reqq);
        return BFA_TRUE;
 }
 
-/**
+/*
  * Call to resume any I/O requests waiting for room in request queue.
  */
 static void
@@ -2591,7 +2590,7 @@ bfa_ioim_qresume(void *cbarg)
 static void
 bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim)
 {
-       /**
+       /*
         * Move IO from itnim queue to fcpim global queue since itnim will be
         * freed.
         */
@@ -2624,13 +2623,13 @@ bfa_ioim_is_abortable(struct bfa_ioim_s *ioim)
        return BFA_TRUE;
 }
 
-/**
+/*
  *     or after the link comes back.
  */
 void
 bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, bfa_boolean_t iotov)
 {
-       /**
+       /*
         * If path tov timer expired, failback with PATHTOV status - these
         * IO requests are not normally retried by IO stack.
         *
@@ -2645,7 +2644,7 @@ bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, bfa_boolean_t iotov)
        }
        bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
 
-       /**
+       /*
         * Move IO to fcpim global queue since itnim will be
         * freed.
         */
@@ -2655,11 +2654,11 @@ bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, bfa_boolean_t iotov)
 
 
 
-/**
+/*
  *  hal_ioim_friend
  */
 
-/**
+/*
  * Memory allocation and initialization.
  */
 void
@@ -2671,7 +2670,7 @@ bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
        u8                      *snsinfo;
        u32             snsbufsz;
 
-       /**
+       /*
         * claim memory first
         */
        ioim = (struct bfa_ioim_s *) bfa_meminfo_kva(minfo);
@@ -2682,7 +2681,7 @@ bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
        fcpim->ioim_sp_arr = iosp;
        bfa_meminfo_kva(minfo) = (u8 *) (iosp + fcpim->num_ioim_reqs);
 
-       /**
+       /*
         * Claim DMA memory for per IO sense data.
         */
        snsbufsz = fcpim->num_ioim_reqs * BFI_IOIM_SNSLEN;
@@ -2694,7 +2693,7 @@ bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
        snsinfo = fcpim->snsbase.kva;
        bfa_iocfc_set_snsbase(fcpim->bfa, fcpim->snsbase.pa);
 
-       /**
+       /*
         * Initialize ioim free queues
         */
        INIT_LIST_HEAD(&fcpim->ioim_free_q);
@@ -2706,7 +2705,7 @@ bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
                /*
                 * initialize IOIM
                 */
-               bfa_os_memset(ioim, 0, sizeof(struct bfa_ioim_s));
+               memset(ioim, 0, sizeof(struct bfa_ioim_s));
                ioim->iotag   = i;
                ioim->bfa     = fcpim->bfa;
                ioim->fcpim   = fcpim;
@@ -2723,7 +2722,7 @@ bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
        }
 }
 
-/**
+/*
  * Driver detach time call.
  */
 void
@@ -2740,7 +2739,7 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
        u16     iotag;
        enum bfa_ioim_event evt = BFA_IOIM_SM_COMP;
 
-       iotag = bfa_os_ntohs(rsp->io_tag);
+       iotag = be16_to_cpu(rsp->io_tag);
 
        ioim = BFA_IOIM_FROM_TAG(fcpim, iotag);
        bfa_assert(ioim->iotag == iotag);
@@ -2750,7 +2749,7 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
        bfa_trc(ioim->bfa, rsp->reuse_io_tag);
 
        if (bfa_sm_cmp_state(ioim, bfa_ioim_sm_active))
-               bfa_os_assign(ioim->iosp->comp_rspmsg, *m);
+               ioim->iosp->comp_rspmsg = *m;
 
        switch (rsp->io_status) {
        case BFI_IOIM_STS_OK:
@@ -2823,7 +2822,7 @@ bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
        struct bfa_ioim_s *ioim;
        u16     iotag;
 
-       iotag = bfa_os_ntohs(rsp->io_tag);
+       iotag = be16_to_cpu(rsp->io_tag);
 
        ioim = BFA_IOIM_FROM_TAG(fcpim, iotag);
        bfa_assert(ioim->iotag == iotag);
@@ -2837,7 +2836,7 @@ bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
 void
 bfa_ioim_profile_start(struct bfa_ioim_s *ioim)
 {
-       ioim->start_time = bfa_os_get_clock();
+       ioim->start_time = jiffies;
 }
 
 void
@@ -2845,7 +2844,7 @@ bfa_ioim_profile_comp(struct bfa_ioim_s *ioim)
 {
        u32 fcp_dl = bfa_cb_ioim_get_size(ioim->dio);
        u32 index = bfa_ioim_get_index(fcp_dl);
-       u64 end_time = bfa_os_get_clock();
+       u64 end_time = jiffies;
        struct bfa_itnim_latency_s *io_lat =
                        &(ioim->itnim->ioprofile.io_latency);
        u32 val = (u32)(end_time - ioim->start_time);
@@ -2859,7 +2858,7 @@ bfa_ioim_profile_comp(struct bfa_ioim_s *ioim)
                io_lat->max[index] : val;
        io_lat->avg[index] += val;
 }
-/**
+/*
  * Called by itnim to clean up IO while going offline.
  */
 void
@@ -2882,7 +2881,7 @@ bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim, struct bfa_tskim_s *tskim)
        bfa_sm_send_event(ioim, BFA_IOIM_SM_CLEANUP);
 }
 
-/**
+/*
  * IOC failure handling.
  */
 void
@@ -2893,7 +2892,7 @@ bfa_ioim_iocdisable(struct bfa_ioim_s *ioim)
        bfa_sm_send_event(ioim, BFA_IOIM_SM_HWFAIL);
 }
 
-/**
+/*
  * IO offline TOV popped. Fail the pending IO.
  */
 void
@@ -2905,11 +2904,11 @@ bfa_ioim_tov(struct bfa_ioim_s *ioim)
 
 
 
-/**
+/*
  *  hal_ioim_api
  */
 
-/**
+/*
  * Allocate IOIM resource for initiator mode I/O request.
  */
 struct bfa_ioim_s *
@@ -2919,7 +2918,7 @@ bfa_ioim_alloc(struct bfa_s *bfa, struct bfad_ioim_s *dio,
        struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
        struct bfa_ioim_s *ioim;
 
-       /**
+       /*
         * alocate IOIM resource
         */
        bfa_q_deq(&fcpim->ioim_free_q, &ioim);
@@ -2970,7 +2969,7 @@ bfa_ioim_start(struct bfa_ioim_s *ioim)
 
        bfa_ioim_cb_profile_start(ioim->fcpim, ioim);
 
-       /**
+       /*
         * Obtain the queue over which this request has to be issued
         */
        ioim->reqq = bfa_fcpim_ioredirect_enabled(ioim->bfa) ?
@@ -2980,7 +2979,7 @@ bfa_ioim_start(struct bfa_ioim_s *ioim)
        bfa_sm_send_event(ioim, BFA_IOIM_SM_START);
 }
 
-/**
+/*
  * Driver I/O abort request.
  */
 bfa_status_t
@@ -2999,11 +2998,11 @@ bfa_ioim_abort(struct bfa_ioim_s *ioim)
 }
 
 
-/**
+/*
  *  BFA TSKIM state machine functions
  */
 
-/**
+/*
  *     Task management command beginning state.
  */
 static void
@@ -3016,7 +3015,7 @@ bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
                bfa_sm_set_state(tskim, bfa_tskim_sm_active);
                bfa_tskim_gather_ios(tskim);
 
-               /**
+               /*
                 * If device is offline, do not send TM on wire. Just cleanup
                 * any pending IO requests and complete TM request.
                 */
@@ -3040,7 +3039,7 @@ bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
        }
 }
 
-/**
+/*
  * brief
  *     TM command is active, awaiting completion from firmware to
  *     cleanup IO requests in TM scope.
@@ -3077,7 +3076,7 @@ bfa_tskim_sm_active(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
        }
 }
 
-/**
+/*
  *     An active TM is being cleaned up since ITN is offline. Awaiting cleanup
  *     completion event from firmware.
  */
@@ -3088,7 +3087,7 @@ bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
 
        switch (event) {
        case BFA_TSKIM_SM_DONE:
-               /**
+               /*
                 * Ignore and wait for ABORT completion from firmware.
                 */
                break;
@@ -3121,7 +3120,7 @@ bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
                break;
 
        case BFA_TSKIM_SM_CLEANUP:
-               /**
+               /*
                 * Ignore, TM command completed on wire.
                 * Notify TM conmpletion on IO cleanup completion.
                 */
@@ -3138,7 +3137,7 @@ bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
        }
 }
 
-/**
+/*
  *     Task management command is waiting for room in request CQ
  */
 static void
@@ -3153,7 +3152,7 @@ bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
                break;
 
        case BFA_TSKIM_SM_CLEANUP:
-               /**
+               /*
                 * No need to send TM on wire since ITN is offline.
                 */
                bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup);
@@ -3173,7 +3172,7 @@ bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
        }
 }
 
-/**
+/*
  *     Task management command is active, awaiting for room in request CQ
  *     to send clean up request.
  */
@@ -3186,7 +3185,7 @@ bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
        switch (event) {
        case BFA_TSKIM_SM_DONE:
                bfa_reqq_wcancel(&tskim->reqq_wait);
-               /**
+               /*
                 *
                 * Fall through !!!
                 */
@@ -3208,7 +3207,7 @@ bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
        }
 }
 
-/**
+/*
  *     BFA callback is pending
  */
 static void
@@ -3236,7 +3235,7 @@ bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
 
 
 
-/**
+/*
  *  hal_tskim_private
  */
 
@@ -3289,7 +3288,7 @@ bfa_tskim_match_scope(struct bfa_tskim_s *tskim, lun_t lun)
        return BFA_FALSE;
 }
 
-/**
+/*
  *     Gather affected IO requests and task management commands.
  */
 static void
@@ -3301,7 +3300,7 @@ bfa_tskim_gather_ios(struct bfa_tskim_s *tskim)
 
        INIT_LIST_HEAD(&tskim->io_q);
 
-       /**
+       /*
         * Gather any active IO requests first.
         */
        list_for_each_safe(qe, qen, &itnim->io_q) {
@@ -3313,7 +3312,7 @@ bfa_tskim_gather_ios(struct bfa_tskim_s *tskim)
                }
        }
 
-       /**
+       /*
         * Failback any pending IO requests immediately.
         */
        list_for_each_safe(qe, qen, &itnim->pending_q) {
@@ -3327,7 +3326,7 @@ bfa_tskim_gather_ios(struct bfa_tskim_s *tskim)
        }
 }
 
-/**
+/*
  *     IO cleanup completion
  */
 static void
@@ -3339,7 +3338,7 @@ bfa_tskim_cleanp_comp(void *tskim_cbarg)
        bfa_sm_send_event(tskim, BFA_TSKIM_SM_IOS_DONE);
 }
 
-/**
+/*
  *     Gather affected IO requests and task management commands.
  */
 static void
@@ -3359,7 +3358,7 @@ bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim)
        bfa_wc_wait(&tskim->wc);
 }
 
-/**
+/*
  *     Send task management request to firmware.
  */
 static bfa_boolean_t
@@ -3368,33 +3367,33 @@ bfa_tskim_send(struct bfa_tskim_s *tskim)
        struct bfa_itnim_s *itnim = tskim->itnim;
        struct bfi_tskim_req_s *m;
 
-       /**
+       /*
         * check for room in queue to send request now
         */
        m = bfa_reqq_next(tskim->bfa, itnim->reqq);
        if (!m)
                return BFA_FALSE;
 
-       /**
+       /*
         * build i/o request message next
         */
        bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_TM_REQ,
                        bfa_lpuid(tskim->bfa));
 
-       m->tsk_tag = bfa_os_htons(tskim->tsk_tag);
+       m->tsk_tag = cpu_to_be16(tskim->tsk_tag);
        m->itn_fhdl = tskim->itnim->rport->fw_handle;
        m->t_secs = tskim->tsecs;
        m->lun = tskim->lun;
        m->tm_flags = tskim->tm_cmnd;
 
-       /**
+       /*
         * queue I/O message to firmware
         */
        bfa_reqq_produce(tskim->bfa, itnim->reqq);
        return BFA_TRUE;
 }
 
-/**
+/*
  *     Send abort request to cleanup an active TM to firmware.
  */
 static bfa_boolean_t
@@ -3403,29 +3402,29 @@ bfa_tskim_send_abort(struct bfa_tskim_s *tskim)
        struct bfa_itnim_s      *itnim = tskim->itnim;
        struct bfi_tskim_abortreq_s     *m;
 
-       /**
+       /*
         * check for room in queue to send request now
         */
        m = bfa_reqq_next(tskim->bfa, itnim->reqq);
        if (!m)
                return BFA_FALSE;
 
-       /**
+       /*
         * build i/o request message next
         */
        bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_ABORT_REQ,
                        bfa_lpuid(tskim->bfa));
 
-       m->tsk_tag  = bfa_os_htons(tskim->tsk_tag);
+       m->tsk_tag  = cpu_to_be16(tskim->tsk_tag);
 
-       /**
+       /*
         * queue I/O message to firmware
         */
        bfa_reqq_produce(tskim->bfa, itnim->reqq);
        return BFA_TRUE;
 }
 
-/**
+/*
  *     Call to resume task management cmnd waiting for room in request queue.
  */
 static void
@@ -3437,7 +3436,7 @@ bfa_tskim_qresume(void *cbarg)
        bfa_sm_send_event(tskim, BFA_TSKIM_SM_QRESUME);
 }
 
-/**
+/*
  * Cleanup IOs associated with a task mangement command on IOC failures.
  */
 static void
@@ -3454,11 +3453,11 @@ bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim)
 
 
 
-/**
+/*
  *  hal_tskim_friend
  */
 
-/**
+/*
  * Notification on completions from related ioim.
  */
 void
@@ -3467,7 +3466,7 @@ bfa_tskim_iodone(struct bfa_tskim_s *tskim)
        bfa_wc_down(&tskim->wc);
 }
 
-/**
+/*
  * Handle IOC h/w failure notification from itnim.
  */
 void
@@ -3478,7 +3477,7 @@ bfa_tskim_iocdisable(struct bfa_tskim_s *tskim)
        bfa_sm_send_event(tskim, BFA_TSKIM_SM_HWFAIL);
 }
 
-/**
+/*
  * Cleanup TM command and associated IOs as part of ITNIM offline.
  */
 void
@@ -3489,7 +3488,7 @@ bfa_tskim_cleanup(struct bfa_tskim_s *tskim)
        bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP);
 }
 
-/**
+/*
  *     Memory allocation and initialization.
  */
 void
@@ -3507,7 +3506,7 @@ bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
                /*
                 * initialize TSKIM
                 */
-               bfa_os_memset(tskim, 0, sizeof(struct bfa_tskim_s));
+               memset(tskim, 0, sizeof(struct bfa_tskim_s));
                tskim->tsk_tag = i;
                tskim->bfa      = fcpim->bfa;
                tskim->fcpim    = fcpim;
@@ -3525,7 +3524,7 @@ bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
 void
 bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim)
 {
-       /**
+       /*
        * @todo
        */
 }
@@ -3536,14 +3535,14 @@ bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
        struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
        struct bfi_tskim_rsp_s *rsp = (struct bfi_tskim_rsp_s *) m;
        struct bfa_tskim_s *tskim;
-       u16     tsk_tag = bfa_os_ntohs(rsp->tsk_tag);
+       u16     tsk_tag = be16_to_cpu(rsp->tsk_tag);
 
        tskim = BFA_TSKIM_FROM_TAG(fcpim, tsk_tag);
        bfa_assert(tskim->tsk_tag == tsk_tag);
 
        tskim->tsk_status = rsp->tsk_status;
 
-       /**
+       /*
         * Firmware sends BFI_TSKIM_STS_ABORTED status for abort
         * requests. All other statuses are for normal completions.
         */
@@ -3558,7 +3557,7 @@ bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
 
 
 
-/**
+/*
  *  hal_tskim_api
  */
 
@@ -3585,7 +3584,7 @@ bfa_tskim_free(struct bfa_tskim_s *tskim)
        list_add_tail(&tskim->qe, &tskim->fcpim->tskim_free_q);
 }
 
-/**
+/*
  *     Start a task management command.
  *
  * @param[in]  tskim   BFA task management command instance
index 3bf343160aacbcfc0a2188ad72b06ed9529bd143..db53717eeb4bb49912a728483c455acabed54d67 100644 (file)
@@ -104,7 +104,7 @@ struct bfa_fcpim_mod_s {
        bfa_fcpim_profile_t     profile_start;
 };
 
-/**
+/*
  * BFA IO (initiator mode)
  */
 struct bfa_ioim_s {
@@ -137,7 +137,7 @@ struct bfa_ioim_sp_s {
        struct bfa_tskim_s      *tskim;         /*  Relevant TM cmd     */
 };
 
-/**
+/*
  * BFA Task management command (initiator mode)
  */
 struct bfa_tskim_s {
@@ -160,7 +160,7 @@ struct bfa_tskim_s {
 };
 
 
-/**
+/*
  * BFA i-t-n (initiator mode)
  */
 struct bfa_itnim_s {
@@ -303,7 +303,7 @@ bfa_status_t        bfa_itnim_get_ioprofile(struct bfa_itnim_s *itnim,
                struct bfa_itnim_ioprofile_s *ioprofile);
 #define bfa_itnim_get_reqq(__ioim) (((struct bfa_ioim_s *)__ioim)->itnim->reqq)
 
-/**
+/*
  *     BFA completion callback for bfa_itnim_online().
  *
  * @param[in]          itnim           FCS or driver itnim instance
@@ -312,7 +312,7 @@ bfa_status_t        bfa_itnim_get_ioprofile(struct bfa_itnim_s *itnim,
  */
 void   bfa_cb_itnim_online(void *itnim);
 
-/**
+/*
  *     BFA completion callback for bfa_itnim_offline().
  *
  * @param[in]          itnim           FCS or driver itnim instance
@@ -323,7 +323,7 @@ void        bfa_cb_itnim_offline(void *itnim);
 void   bfa_cb_itnim_tov_begin(void *itnim);
 void   bfa_cb_itnim_tov(void *itnim);
 
-/**
+/*
  *     BFA notification to FCS/driver for second level error recovery.
  *
  * Atleast one I/O request has timedout and target is unresponsive to
@@ -351,7 +351,7 @@ void                bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim,
                                      bfa_boolean_t iotov);
 
 
-/**
+/*
  *     I/O completion notification.
  *
  * @param[in]          dio                     driver IO structure
@@ -368,7 +368,7 @@ void        bfa_cb_ioim_done(void *bfad, struct bfad_ioim_s *dio,
                                  u8 scsi_status, int sns_len,
                                  u8 *sns_info, s32 residue);
 
-/**
+/*
  *     I/O good completion notification.
  *
  * @param[in]          dio                     driver IO structure
@@ -377,7 +377,7 @@ void        bfa_cb_ioim_done(void *bfad, struct bfad_ioim_s *dio,
  */
 void   bfa_cb_ioim_good_comp(void *bfad, struct bfad_ioim_s *dio);
 
-/**
+/*
  *     I/O abort completion notification
  *
  * @param[in]          dio                     driver IO that was aborted
index 9cebbe30a6782dbf8e8d9fedea033d7f19531d68..c94502dfac664f55fd42080695989d9e1cb1697b 100644 (file)
@@ -15,7 +15,7 @@
  * General Public License for more details.
  */
 
-/**
+/*
  *  bfa_fcs.c BFA FCS main
  */
 
@@ -25,7 +25,7 @@
 
 BFA_TRC_FILE(FCS, FCS);
 
-/**
+/*
  * FCS sub-modules
  */
 struct bfa_fcs_mod_s {
@@ -43,7 +43,7 @@ static struct bfa_fcs_mod_s fcs_modules[] = {
          bfa_fcs_fabric_modexit },
 };
 
-/**
+/*
  *  fcs_api BFA FCS API
  */
 
@@ -58,11 +58,11 @@ bfa_fcs_exit_comp(void *fcs_cbarg)
 
 
 
-/**
+/*
  *  fcs_api BFA FCS API
  */
 
-/**
+/*
  * fcs attach -- called once to initialize data structures at driver attach time
  */
 void
@@ -86,7 +86,7 @@ bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
        }
 }
 
-/**
+/*
  * fcs initialization, called once after bfa initialization is complete
  */
 void
@@ -110,7 +110,7 @@ bfa_fcs_init(struct bfa_fcs_s *fcs)
        }
 }
 
-/**
+/*
  * Start FCS operations.
  */
 void
@@ -119,7 +119,7 @@ bfa_fcs_start(struct bfa_fcs_s *fcs)
        bfa_fcs_fabric_modstart(fcs);
 }
 
-/**
+/*
  *     brief
  *             FCS driver details initialization.
  *
@@ -138,7 +138,7 @@ bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs,
        bfa_fcs_fabric_psymb_init(&fcs->fabric);
 }
 
-/**
+/*
  *     brief
  *             FCS FDMI Driver Parameter Initialization
  *
@@ -154,7 +154,7 @@ bfa_fcs_set_fdmi_param(struct bfa_fcs_s *fcs, bfa_boolean_t fdmi_enable)
        fcs->fdmi_enabled = fdmi_enable;
 
 }
-/**
+/*
  *     brief
  *             FCS instance cleanup and exit.
  *
@@ -196,7 +196,7 @@ bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs)
        bfa_wc_down(&fcs->wc);
 }
 
-/**
+/*
  * Fabric module implementation.
  */
 
@@ -232,11 +232,11 @@ static void bfa_fcs_fabric_flogiacc_comp(void *fcsarg,
                                         u32 rsp_len,
                                         u32 resid_len,
                                         struct fchs_s *rspfchs);
-/**
+/*
  *  fcs_fabric_sm fabric state machine functions
  */
 
-/**
+/*
  * Fabric state machine events
  */
 enum bfa_fcs_fabric_event {
@@ -286,7 +286,7 @@ static void bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric,
                                           enum bfa_fcs_fabric_event event);
 static void    bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric,
                                           enum bfa_fcs_fabric_event event);
-/**
+/*
  *   Beginning state before fabric creation.
  */
 static void
@@ -312,7 +312,7 @@ bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric,
        }
 }
 
-/**
+/*
  *   Beginning state before fabric creation.
  */
 static void
@@ -345,7 +345,7 @@ bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric,
        }
 }
 
-/**
+/*
  *   Link is down, awaiting LINK UP event from port. This is also the
  *   first state at fabric creation.
  */
@@ -375,7 +375,7 @@ bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric,
        }
 }
 
-/**
+/*
  *   FLOGI is in progress, awaiting FLOGI reply.
  */
 static void
@@ -468,7 +468,7 @@ bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric,
        }
 }
 
-/**
+/*
  *   Authentication is in progress, awaiting authentication results.
  */
 static void
@@ -508,7 +508,7 @@ bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric,
        }
 }
 
-/**
+/*
  *   Authentication failed
  */
 static void
@@ -534,7 +534,7 @@ bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric,
        }
 }
 
-/**
+/*
  *   Port is in loopback mode.
  */
 static void
@@ -560,7 +560,7 @@ bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric,
        }
 }
 
-/**
+/*
  *   There is no attached fabric - private loop or NPort-to-NPort topology.
  */
 static void
@@ -593,7 +593,7 @@ bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric,
        }
 }
 
-/**
+/*
  *   Fabric is online - normal operating state.
  */
 static void
@@ -628,7 +628,7 @@ bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
        }
 }
 
-/**
+/*
  *   Exchanging virtual fabric parameters.
  */
 static void
@@ -652,7 +652,7 @@ bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric,
        }
 }
 
-/**
+/*
  *   EVFP exchange complete and VFT tagging is enabled.
  */
 static void
@@ -663,7 +663,7 @@ bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric,
        bfa_trc(fabric->fcs, event);
 }
 
-/**
+/*
  *   Port is isolated after EVFP exchange due to VF_ID mismatch (N and F).
  */
 static void
@@ -684,7 +684,7 @@ bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric,
                fabric->event_arg.swp_vfid);
 }
 
-/**
+/*
  *   Fabric is being deleted, awaiting vport delete completions.
  */
 static void
@@ -714,7 +714,7 @@ bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric,
 
 
 
-/**
+/*
  *  fcs_fabric_private fabric private functions
  */
 
@@ -728,7 +728,7 @@ bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric)
        port_cfg->pwwn = bfa_ioc_get_pwwn(&fabric->fcs->bfa->ioc);
 }
 
-/**
+/*
  * Port Symbolic Name Creation for base port.
  */
 void
@@ -789,7 +789,7 @@ bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric)
        port_cfg->sym_name.symname[BFA_SYMNAME_MAXLEN - 1] = 0;
 }
 
-/**
+/*
  * bfa lps login completion callback
  */
 void
@@ -867,7 +867,7 @@ bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status)
        bfa_trc(fabric->fcs, fabric->is_npiv);
        bfa_trc(fabric->fcs, fabric->is_auth);
 }
-/**
+/*
  *             Allocate and send FLOGI.
  */
 static void
@@ -897,7 +897,7 @@ bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric)
        bfa_fcs_fabric_set_opertype(fabric);
        fabric->stats.fabric_onlines++;
 
-       /**
+       /*
         * notify online event to base and then virtual ports
         */
        bfa_fcs_lport_online(&fabric->bport);
@@ -917,7 +917,7 @@ bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric)
        bfa_trc(fabric->fcs, fabric->fabric_name);
        fabric->stats.fabric_offlines++;
 
-       /**
+       /*
         * notify offline event first to vports and then base port.
         */
        list_for_each_safe(qe, qen, &fabric->vport_q) {
@@ -939,7 +939,7 @@ bfa_fcs_fabric_delay(void *cbarg)
        bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELAYED);
 }
 
-/**
+/*
  * Delete all vports and wait for vport delete completions.
  */
 static void
@@ -965,11 +965,11 @@ bfa_fcs_fabric_delete_comp(void *cbarg)
        bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELCOMP);
 }
 
-/**
+/*
  *  fcs_fabric_public fabric public functions
  */
 
-/**
+/*
  * Attach time initialization.
  */
 void
@@ -978,9 +978,9 @@ bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs)
        struct bfa_fcs_fabric_s *fabric;
 
        fabric = &fcs->fabric;
-       bfa_os_memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s));
+       memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s));
 
-       /**
+       /*
         * Initialize base fabric.
         */
        fabric->fcs = fcs;
@@ -989,7 +989,7 @@ bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs)
        fabric->lps = bfa_lps_alloc(fcs->bfa);
        bfa_assert(fabric->lps);
 
-       /**
+       /*
         * Initialize fabric delete completion handler. Fabric deletion is
         * complete when the last vport delete is complete.
         */
@@ -1007,7 +1007,7 @@ bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs)
        bfa_trc(fcs, 0);
 }
 
-/**
+/*
  *   Module cleanup
  */
 void
@@ -1017,7 +1017,7 @@ bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs)
 
        bfa_trc(fcs, 0);
 
-       /**
+       /*
         * Cleanup base fabric.
         */
        fabric = &fcs->fabric;
@@ -1025,7 +1025,7 @@ bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs)
        bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELETE);
 }
 
-/**
+/*
  * Fabric module start -- kick starts FCS actions
  */
 void
@@ -1038,7 +1038,7 @@ bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs)
        bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_START);
 }
 
-/**
+/*
  *   Suspend fabric activity as part of driver suspend.
  */
 void
@@ -1064,7 +1064,7 @@ bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric)
        return fabric->oper_type;
 }
 
-/**
+/*
  *   Link up notification from BFA physical port module.
  */
 void
@@ -1074,7 +1074,7 @@ bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric)
        bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_UP);
 }
 
-/**
+/*
  *   Link down notification from BFA physical port module.
  */
 void
@@ -1084,7 +1084,7 @@ bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric)
        bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_DOWN);
 }
 
-/**
+/*
  *   A child vport is being created in the fabric.
  *
  *   Call from vport module at vport creation. A list of base port and vports
@@ -1099,7 +1099,7 @@ void
 bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric,
                        struct bfa_fcs_vport_s *vport)
 {
-       /**
+       /*
         * - add vport to fabric's vport_q
         */
        bfa_trc(fabric->fcs, fabric->vf_id);
@@ -1109,7 +1109,7 @@ bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric,
        bfa_wc_up(&fabric->wc);
 }
 
-/**
+/*
  *   A child vport is being deleted from fabric.
  *
  *   Vport is being deleted.
@@ -1123,7 +1123,7 @@ bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric,
        bfa_wc_down(&fabric->wc);
 }
 
-/**
+/*
  *   Base port is deleted.
  */
 void
@@ -1133,7 +1133,7 @@ bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric)
 }
 
 
-/**
+/*
  *    Check if fabric is online.
  *
  *   param[in] fabric - Fabric instance. This can be a base fabric or vf.
@@ -1146,7 +1146,7 @@ bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric)
        return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_online);
 }
 
-/**
+/*
  *     brief
  *
  */
@@ -1158,7 +1158,7 @@ bfa_fcs_fabric_addvf(struct bfa_fcs_fabric_s *vf, struct bfa_fcs_s *fcs,
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  * Lookup for a vport withing a fabric given its pwwn
  */
 struct bfa_fcs_vport_s *
@@ -1176,7 +1176,7 @@ bfa_fcs_fabric_vport_lookup(struct bfa_fcs_fabric_s *fabric, wwn_t pwwn)
        return NULL;
 }
 
-/**
+/*
  *    In a given fabric, return the number of lports.
  *
  *   param[in] fabric - Fabric instance. This can be a base fabric or vf.
@@ -1214,7 +1214,7 @@ bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric)
 
        return oui;
 }
-/**
+/*
  *             Unsolicited frame receive handling.
  */
 void
@@ -1230,7 +1230,7 @@ bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
        bfa_trc(fabric->fcs, len);
        bfa_trc(fabric->fcs, pid);
 
-       /**
+       /*
         * Look for our own FLOGI frames being looped back. This means an
         * external loopback cable is in place. Our own FLOGI frames are
         * sometimes looped back when switch port gets temporarily bypassed.
@@ -1242,7 +1242,7 @@ bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
                return;
        }
 
-       /**
+       /*
         * FLOGI/EVFP exchanges should be consumed by base fabric.
         */
        if (fchs->d_id == bfa_os_hton3b(FC_FABRIC_PORT)) {
@@ -1252,7 +1252,7 @@ bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
        }
 
        if (fabric->bport.pid == pid) {
-               /**
+               /*
                 * All authentication frames should be routed to auth
                 */
                bfa_trc(fabric->fcs, els_cmd->els_code);
@@ -1266,7 +1266,7 @@ bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
                return;
        }
 
-       /**
+       /*
         * look for a matching local port ID
         */
        list_for_each(qe, &fabric->vport_q) {
@@ -1280,7 +1280,7 @@ bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
        bfa_fcs_lport_uf_recv(&fabric->bport, fchs, len);
 }
 
-/**
+/*
  *             Unsolicited frames to be processed by fabric.
  */
 static void
@@ -1304,7 +1304,7 @@ bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
        }
 }
 
-/**
+/*
  *     Process incoming FLOGI
  */
 static void
@@ -1329,7 +1329,7 @@ bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric,
                return;
        }
 
-       fabric->bb_credit = bfa_os_ntohs(flogi->csp.bbcred);
+       fabric->bb_credit = be16_to_cpu(flogi->csp.bbcred);
        bport->port_topo.pn2n.rem_port_wwn = flogi->port_name;
        bport->port_topo.pn2n.reply_oxid = fchs->ox_id;
 
@@ -1351,7 +1351,7 @@ bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric)
        struct fchs_s   fchs;
 
        fcxp = bfa_fcs_fcxp_alloc(fabric->fcs);
-       /**
+       /*
         * Do not expect this failure -- expect remote node to retry
         */
        if (!fcxp)
@@ -1370,7 +1370,7 @@ bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric)
                      FC_MAX_PDUSZ, 0);
 }
 
-/**
+/*
  *   Flogi Acc completion callback.
  */
 static void
@@ -1417,130 +1417,7 @@ bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
        }
 }
 
-/**
- *  fcs_vf_api virtual fabrics API
- */
-
-/**
- * Enable VF mode.
- *
- * @param[in]          fcs             fcs module instance
- * @param[in]          vf_id           default vf_id of port, FC_VF_ID_NULL
- *                                     to use standard default vf_id of 1.
- *
- * @retval     BFA_STATUS_OK           vf mode is enabled
- * @retval     BFA_STATUS_BUSY         Port is active. Port must be disabled
- *                                     before VF mode can be enabled.
- */
-bfa_status_t
-bfa_fcs_vf_mode_enable(struct bfa_fcs_s *fcs, u16 vf_id)
-{
-       return BFA_STATUS_OK;
-}
-
-/**
- * Disable VF mode.
- *
- * @param[in]          fcs             fcs module instance
- *
- * @retval     BFA_STATUS_OK           vf mode is disabled
- * @retval     BFA_STATUS_BUSY         VFs are present and being used. All
- *                                     VFs must be deleted before disabling
- *                                     VF mode.
- */
-bfa_status_t
-bfa_fcs_vf_mode_disable(struct bfa_fcs_s *fcs)
-{
-       return BFA_STATUS_OK;
-}
-
-/**
- *  Create a new VF instance.
- *
- *  A new VF is created using the given VF configuration. A VF is identified
- *  by VF id. No duplicate VF creation is allowed with the same VF id. Once
- *  a VF is created, VF is automatically started after link initialization
- *  and EVFP exchange is completed.
- *
- *     param[in] vf     -      FCS vf data structure. Memory is
- *                             allocated by caller (driver)
- *     param[in] fcs    -      FCS module
- *     param[in] vf_cfg -      VF configuration
- *     param[in] vf_drv -      Opaque handle back to the driver's
- *                             virtual vf structure
- *
- *     retval BFA_STATUS_OK VF creation is successful
- *     retval BFA_STATUS_FAILED VF creation failed
- *     retval BFA_STATUS_EEXIST A VF exists with the given vf_id
- */
-bfa_status_t
-bfa_fcs_vf_create(bfa_fcs_vf_t *vf, struct bfa_fcs_s *fcs, u16 vf_id,
-                 struct bfa_lport_cfg_s *port_cfg, struct bfad_vf_s *vf_drv)
-{
-       bfa_trc(fcs, vf_id);
-       return BFA_STATUS_OK;
-}
-
-/**
- *     Use this function to delete a BFA VF object. VF object should
- *     be stopped before this function call.
- *
- *     param[in] vf - pointer to bfa_vf_t.
- *
- *     retval BFA_STATUS_OK    On vf deletion success
- *     retval BFA_STATUS_BUSY VF is not in a stopped state
- *     retval BFA_STATUS_INPROGRESS VF deletion in in progress
- */
-bfa_status_t
-bfa_fcs_vf_delete(bfa_fcs_vf_t *vf)
-{
-       bfa_trc(vf->fcs, vf->vf_id);
-       return BFA_STATUS_OK;
-}
-
-
-/**
- *     Returns attributes of the given VF.
- *
- *     param[in]       vf      pointer to bfa_vf_t.
- *     param[out] vf_attr      vf attributes returned
- *
- *     return None
- */
-void
-bfa_fcs_vf_get_attr(bfa_fcs_vf_t *vf, struct bfa_vf_attr_s *vf_attr)
-{
-       bfa_trc(vf->fcs, vf->vf_id);
-}
-
-/**
- *     Return statistics associated with the given vf.
- *
- *     param[in] vf            pointer to bfa_vf_t.
- *     param[out] vf_stats     vf statistics returned
- *
- *     @return None
- */
-void
-bfa_fcs_vf_get_stats(bfa_fcs_vf_t *vf, struct bfa_vf_stats_s *vf_stats)
-{
-       bfa_os_memcpy(vf_stats, &vf->stats, sizeof(struct bfa_vf_stats_s));
-}
-
-/**
- *     clear statistics associated with the given vf.
- *
- *     param[in]       vf      pointer to bfa_vf_t.
- *
- *     @return None
- */
-void
-bfa_fcs_vf_clear_stats(bfa_fcs_vf_t *vf)
-{
-       bfa_os_memset(&vf->stats, 0, sizeof(struct bfa_vf_stats_s));
-}
-
-/**
+/*
  *     Returns FCS vf structure for a given vf_id.
  *
  *     param[in]       vf_id - VF_ID
@@ -1558,81 +1435,7 @@ bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id)
        return NULL;
 }
 
-/**
- *     Return the list of VFs configured.
- *
- *     param[in]       fcs     fcs module instance
- *     param[out]      vf_ids  returned list of vf_ids
- *     param[in,out]   nvfs    in:size of vf_ids array,
- *                             out:total elements present,
- *                             actual elements returned is limited by the size
- *
- *     return Driver VF structure
- */
-void
-bfa_fcs_vf_list(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs)
-{
-       bfa_trc(fcs, *nvfs);
-}
-
-/**
- *     Return the list of all VFs visible from fabric.
- *
- *     param[in]       fcs     fcs module instance
- *     param[out]      vf_ids  returned list of vf_ids
- *     param[in,out]   nvfs    in:size of vf_ids array,
- *                             out:total elements present,
- *                             actual elements returned is limited by the size
- *
- *     return Driver VF structure
- */
-void
-bfa_fcs_vf_list_all(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs)
-{
-       bfa_trc(fcs, *nvfs);
-}
-
-/**
- *     Return the list of local logical ports present in the given VF.
- *
- *     param[in]       vf      vf for which logical ports are returned
- *     param[out]      lpwwn   returned logical port wwn list
- *     param[in,out]   nlports in:size of lpwwn list;
- *                             out:total elements present,
- *                             actual elements returned is limited by the size
- */
-void
-bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t lpwwn[], int *nlports)
-{
-       struct list_head        *qe;
-       struct bfa_fcs_vport_s *vport;
-       int     i;
-       struct bfa_fcs_s      *fcs;
-
-       if (vf == NULL || lpwwn == NULL || *nlports == 0)
-               return;
-
-       fcs = vf->fcs;
-
-       bfa_trc(fcs, vf->vf_id);
-       bfa_trc(fcs, (u32) *nlports);
-
-       i = 0;
-       lpwwn[i++] = vf->bport.port_cfg.pwwn;
-
-       list_for_each(qe, &vf->vport_q) {
-               if (i >= *nlports)
-                       break;
-
-               vport = (struct bfa_fcs_vport_s *) qe;
-               lpwwn[i++] = vport->lport.port_cfg.pwwn;
-       }
-
-       bfa_trc(fcs, i);
-       *nlports = i;
-}
-
-/**
+/*
  * BFA FCS PPORT ( physical port)
  */
 static void
@@ -1662,11 +1465,11 @@ bfa_fcs_port_attach(struct bfa_fcs_s *fcs)
        bfa_fcport_event_register(fcs->bfa, bfa_fcs_port_event_handler, fcs);
 }
 
-/**
+/*
  * BFA FCS UF ( Unsolicited Frames)
  */
 
-/**
+/*
  *             BFA callback for unsolicited frame receive handler.
  *
  * @param[in]          cbarg           callback arg for receive handler
@@ -1683,7 +1486,7 @@ bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf)
        struct fc_vft_s *vft;
        struct bfa_fcs_fabric_s *fabric;
 
-       /**
+       /*
         * check for VFT header
         */
        if (fchs->routing == FC_RTG_EXT_HDR &&
@@ -1695,7 +1498,7 @@ bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf)
                else
                        fabric = bfa_fcs_vf_lookup(fcs, (u16) vft->vf_id);
 
-               /**
+               /*
                 * drop frame if vfid is unknown
                 */
                if (!fabric) {
@@ -1705,7 +1508,7 @@ bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf)
                        return;
                }
 
-               /**
+               /*
                 * skip vft header
                 */
                fchs = (struct fchs_s *) (vft + 1);
index d75045df1e7e2202f817eb20cf8f70ee5423c14f..9cb6a55977c3ad932642a80a5eecff8cb803fe24 100644 (file)
@@ -196,7 +196,7 @@ struct bfa_fcs_fabric_s {
 #define bfa_fcs_fabric_is_switched(__f)                        \
        ((__f)->fab_type == BFA_FCS_FABRIC_SWITCHED)
 
-/**
+/*
  *   The design calls for a single implementation of base fabric and vf.
  */
 #define bfa_fcs_vf_t struct bfa_fcs_fabric_s
@@ -216,7 +216,7 @@ struct bfa_fcs_fabric_s;
 
 #define bfa_fcs_lport_t struct bfa_fcs_lport_s
 
-/**
+/*
  * Symbolic Name related defines
  *  Total bytes 255.
  *  Physical Port's symbolic name 128 bytes.
@@ -239,7 +239,7 @@ struct bfa_fcs_fabric_s;
 #define BFA_FCS_PORT_SYMBNAME_OSINFO_SZ                        48
 #define BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ               16
 
-/**
+/*
  * Get FC port ID for a logical port.
  */
 #define bfa_fcs_lport_get_fcid(_lport) ((_lport)->pid)
@@ -262,7 +262,7 @@ bfa_fcs_lport_get_drvport(struct bfa_fcs_lport_s *port)
 #define bfa_fcs_lport_get_fabric_ipaddr(_lport)                \
                ((_lport)->fabric->fabric_ip_addr)
 
-/**
+/*
  * bfa fcs port public functions
  */
 
@@ -342,7 +342,7 @@ struct bfa_fcs_vport_s {
 #define bfa_fcs_vport_get_port(vport)                  \
        ((struct bfa_fcs_lport_s  *)(&vport->port))
 
-/**
+/*
  * bfa fcs vport public functions
  */
 bfa_status_t bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport,
@@ -393,7 +393,7 @@ struct bfa_fcs_rpf_s {
        enum bfa_port_speed     rpsc_speed;
        /*  Current Speed from RPSC. O if RPSC fails */
        enum bfa_port_speed     assigned_speed;
-       /**
+       /*
         * Speed assigned by the user.  will be used if RPSC is
         * not supported by the rport.
         */
@@ -434,7 +434,7 @@ bfa_fcs_rport_get_halrport(struct bfa_fcs_rport_s *rport)
        return rport->bfa_rport;
 }
 
-/**
+/*
  * bfa fcs rport API functions
  */
 bfa_status_t bfa_fcs_rport_add(struct bfa_fcs_lport_s *port, wwn_t *pwwn,
@@ -573,7 +573,7 @@ bfa_fcs_itnim_get_halitn(struct bfa_fcs_itnim_s *itnim)
        return itnim->bfa_itnim;
 }
 
-/**
+/*
  * bfa fcs FCP Initiator mode API functions
  */
 void bfa_fcs_itnim_get_attr(struct bfa_fcs_itnim_s *itnim,
@@ -677,22 +677,9 @@ void bfa_fcs_exit(struct bfa_fcs_s *fcs);
 void bfa_fcs_trc_init(struct bfa_fcs_s *fcs, struct bfa_trc_mod_s *trcmod);
 void           bfa_fcs_start(struct bfa_fcs_s *fcs);
 
-/**
+/*
  * bfa fcs vf public functions
  */
-bfa_status_t bfa_fcs_vf_mode_enable(struct bfa_fcs_s *fcs, u16 vf_id);
-bfa_status_t bfa_fcs_vf_mode_disable(struct bfa_fcs_s *fcs);
-bfa_status_t bfa_fcs_vf_create(bfa_fcs_vf_t *vf, struct bfa_fcs_s *fcs,
-                              u16 vf_id, struct bfa_lport_cfg_s *port_cfg,
-                              struct bfad_vf_s *vf_drv);
-bfa_status_t bfa_fcs_vf_delete(bfa_fcs_vf_t *vf);
-void bfa_fcs_vf_list(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs);
-void bfa_fcs_vf_list_all(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs);
-void bfa_fcs_vf_get_attr(bfa_fcs_vf_t *vf, struct bfa_vf_attr_s *vf_attr);
-void bfa_fcs_vf_get_stats(bfa_fcs_vf_t *vf,
-                         struct bfa_vf_stats_s *vf_stats);
-void bfa_fcs_vf_clear_stats(bfa_fcs_vf_t *vf);
-void bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t vpwwn[], int *nports);
 bfa_fcs_vf_t *bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id);
 u16 bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric);
 
@@ -729,11 +716,11 @@ u16 bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric);
 void bfa_fcs_uf_attach(struct bfa_fcs_s *fcs);
 void bfa_fcs_port_attach(struct bfa_fcs_s *fcs);
 
-/**
+/*
  * BFA FCS callback interfaces
  */
 
-/**
+/*
  * fcb Main fcs callbacks
  */
 
@@ -742,7 +729,7 @@ struct bfad_vf_s;
 struct bfad_vport_s;
 struct bfad_rport_s;
 
-/**
+/*
  * lport callbacks
  */
 struct bfad_port_s *bfa_fcb_lport_new(struct bfad_s *bfad,
@@ -754,19 +741,19 @@ void bfa_fcb_lport_delete(struct bfad_s *bfad, enum bfa_lport_role roles,
                          struct bfad_vf_s *vf_drv,
                          struct bfad_vport_s *vp_drv);
 
-/**
+/*
  * vport callbacks
  */
 void bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s);
 
-/**
+/*
  * rport callbacks
  */
 bfa_status_t bfa_fcb_rport_alloc(struct bfad_s *bfad,
                                 struct bfa_fcs_rport_s **rport,
                                 struct bfad_rport_s **rport_drv);
 
-/**
+/*
  * itnim callbacks
  */
 void bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim,
index 569dfefab70d7a1ae71143895e08571d0b015b5c..9662bcdeb41d64c50ab7530fd34ab17d543fc44c 100644 (file)
@@ -15,7 +15,7 @@
  * General Public License for more details.
  */
 
-/**
+/*
  *  fcpim.c - FCP initiator mode i-t nexus state machine
  */
 
@@ -38,7 +38,7 @@ static void   bfa_fcs_itnim_prli_response(void *fcsarg,
                            bfa_status_t req_status, u32 rsp_len,
                            u32 resid_len, struct fchs_s *rsp_fchs);
 
-/**
+/*
  *  fcs_itnim_sm FCS itnim state machine events
  */
 
@@ -84,7 +84,7 @@ static struct bfa_sm_table_s itnim_sm_table[] = {
        {BFA_SM(bfa_fcs_itnim_sm_initiator), BFA_ITNIM_INITIATIOR},
 };
 
-/**
+/*
  *  fcs_itnim_sm FCS itnim state machine
  */
 
@@ -494,11 +494,11 @@ bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim)
 
 
 
-/**
+/*
  *  itnim_public FCS ITNIM public interfaces
  */
 
-/**
+/*
  *     Called by rport when a new rport is created.
  *
  * @param[in] rport    -  remote port.
@@ -554,7 +554,7 @@ bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport)
        return itnim;
 }
 
-/**
+/*
  *     Called by rport to delete  the instance of FCPIM.
  *
  * @param[in] rport    -  remote port.
@@ -566,7 +566,7 @@ bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim)
        bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_DELETE);
 }
 
-/**
+/*
  * Notification from rport that PLOGI is complete to initiate FC-4 session.
  */
 void
@@ -586,7 +586,7 @@ bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim)
        }
 }
 
-/**
+/*
  * Called by rport to handle a remote device offline.
  */
 void
@@ -596,7 +596,7 @@ bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim)
        bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_OFFLINE);
 }
 
-/**
+/*
  * Called by rport when remote port is known to be an initiator from
  * PRLI received.
  */
@@ -608,7 +608,7 @@ bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim)
        bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
 }
 
-/**
+/*
  * Called by rport to check if the itnim is online.
  */
 bfa_status_t
@@ -625,7 +625,7 @@ bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim)
        }
 }
 
-/**
+/*
  * BFA completion callback for bfa_itnim_online().
  */
 void
@@ -637,7 +637,7 @@ bfa_cb_itnim_online(void *cbarg)
        bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE);
 }
 
-/**
+/*
  * BFA completion callback for bfa_itnim_offline().
  */
 void
@@ -649,7 +649,7 @@ bfa_cb_itnim_offline(void *cb_arg)
        bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE);
 }
 
-/**
+/*
  * Mark the beginning of PATH TOV handling. IO completion callbacks
  * are still pending.
  */
@@ -661,7 +661,7 @@ bfa_cb_itnim_tov_begin(void *cb_arg)
        bfa_trc(itnim->fcs, itnim->rport->pwwn);
 }
 
-/**
+/*
  * Mark the end of PATH TOV handling. All pending IOs are already cleaned up.
  */
 void
@@ -674,7 +674,7 @@ bfa_cb_itnim_tov(void *cb_arg)
        itnim_drv->state = ITNIM_STATE_TIMEOUT;
 }
 
-/**
+/*
  *             BFA notification to FCS/driver for second level error recovery.
  *
  * Atleast one I/O request has timedout and target is unresponsive to
@@ -736,7 +736,7 @@ bfa_fcs_itnim_stats_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn,
        if (itnim == NULL)
                return BFA_STATUS_NO_FCPIM_NEXUS;
 
-       bfa_os_memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s));
+       memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s));
 
        return BFA_STATUS_OK;
 }
@@ -753,7 +753,7 @@ bfa_fcs_itnim_stats_clear(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
        if (itnim == NULL)
                return BFA_STATUS_NO_FCPIM_NEXUS;
 
-       bfa_os_memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s));
+       memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s));
        return BFA_STATUS_OK;
 }
 
index b522bf30247a62d2f63be931b2c46dc73df4a583..377cbfff6f2ec88a467b6e8014d27c91d3b4a0c3 100644 (file)
  * General Public License for more details.
  */
 
-/**
- *  bfa_fcs_lport.c BFA FCS port
- */
-
 #include "bfa_fcs.h"
 #include "bfa_fcbuild.h"
 #include "bfa_fc.h"
 
 BFA_TRC_FILE(FCS, PORT);
 
-/**
- * Forward declarations
- */
-
 static void     bfa_fcs_lport_send_ls_rjt(struct bfa_fcs_lport_s *port,
                                         struct fchs_s *rx_fchs, u8 reason_code,
                                         u8 reason_code_expl);
@@ -72,7 +64,7 @@ static struct {
                        bfa_fcs_lport_n2n_offline},
        };
 
-/**
+/*
  *  fcs_port_sm FCS logical port state machine
  */
 
@@ -240,7 +232,7 @@ bfa_fcs_lport_sm_deleting(
        }
 }
 
-/**
+/*
  *  fcs_port_pvt
  */
 
@@ -272,7 +264,7 @@ bfa_fcs_lport_send_ls_rjt(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs,
                          FC_MAX_PDUSZ, 0);
 }
 
-/**
+/*
  * Process incoming plogi from a remote port.
  */
 static void
@@ -303,7 +295,7 @@ bfa_fcs_lport_plogi(struct bfa_fcs_lport_s *port,
                return;
        }
 
-       /**
+       /*
         * Direct Attach P2P mode : verify address assigned by the r-port.
         */
        if ((!bfa_fcs_fabric_is_switched(port->fabric)) &&
@@ -319,12 +311,12 @@ bfa_fcs_lport_plogi(struct bfa_fcs_lport_s *port,
                port->pid  = rx_fchs->d_id;
        }
 
-       /**
+       /*
         * First, check if we know the device by pwwn.
         */
        rport = bfa_fcs_lport_get_rport_by_pwwn(port, plogi->port_name);
        if (rport) {
-               /**
+               /*
                 * Direct Attach P2P mode : handle address assigned by r-port.
                 */
                if ((!bfa_fcs_fabric_is_switched(port->fabric)) &&
@@ -337,37 +329,37 @@ bfa_fcs_lport_plogi(struct bfa_fcs_lport_s *port,
                return;
        }
 
-       /**
+       /*
         * Next, lookup rport by PID.
         */
        rport = bfa_fcs_lport_get_rport_by_pid(port, rx_fchs->s_id);
        if (!rport) {
-               /**
+               /*
                 * Inbound PLOGI from a new device.
                 */
                bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
                return;
        }
 
-       /**
+       /*
         * Rport is known only by PID.
         */
        if (rport->pwwn) {
-               /**
+               /*
                 * This is a different device with the same pid. Old device
                 * disappeared. Send implicit LOGO to old device.
                 */
                bfa_assert(rport->pwwn != plogi->port_name);
                bfa_fcs_rport_logo_imp(rport);
 
-               /**
+               /*
                 * Inbound PLOGI from a new device (with old PID).
                 */
                bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
                return;
        }
 
-       /**
+       /*
         * PLOGI crossing each other.
         */
        bfa_assert(rport->pwwn == WWN_NULL);
@@ -479,12 +471,12 @@ static void
 bfa_fs_port_get_gen_topo_data(struct bfa_fcs_lport_s *port,
                        struct fc_rnid_general_topology_data_s *gen_topo_data)
 {
-       bfa_os_memset(gen_topo_data, 0,
+       memset(gen_topo_data, 0,
                      sizeof(struct fc_rnid_general_topology_data_s));
 
-       gen_topo_data->asso_type = bfa_os_htonl(RNID_ASSOCIATED_TYPE_HOST);
+       gen_topo_data->asso_type = cpu_to_be32(RNID_ASSOCIATED_TYPE_HOST);
        gen_topo_data->phy_port_num = 0;        /* @todo */
-       gen_topo_data->num_attached_nodes = bfa_os_htonl(1);
+       gen_topo_data->num_attached_nodes = cpu_to_be32(1);
 }
 
 static void
@@ -598,10 +590,10 @@ bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port)
 
 
 
-/**
+/*
  *  fcs_lport_api BFA FCS port API
  */
-/**
+/*
  *   Module initialization
  */
 void
@@ -610,7 +602,7 @@ bfa_fcs_lport_modinit(struct bfa_fcs_s *fcs)
 
 }
 
-/**
+/*
  *   Module cleanup
  */
 void
@@ -619,7 +611,7 @@ bfa_fcs_lport_modexit(struct bfa_fcs_s *fcs)
        bfa_fcs_modexit_comp(fcs);
 }
 
-/**
+/*
  * Unsolicited frame receive handling.
  */
 void
@@ -637,7 +629,7 @@ bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport,
                return;
        }
 
-       /**
+       /*
         * First, handle ELSs that donot require a login.
         */
        /*
@@ -673,7 +665,7 @@ bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport,
                        bfa_fcs_lport_abts_acc(lport, fchs);
                return;
        }
-       /**
+       /*
         * look for a matching remote port ID
         */
        rport = bfa_fcs_lport_get_rport_by_pid(lport, pid);
@@ -686,7 +678,7 @@ bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport,
                return;
        }
 
-       /**
+       /*
         * Only handles ELS frames for now.
         */
        if (fchs->type != FC_TYPE_ELS) {
@@ -702,20 +694,20 @@ bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport,
        }
 
        if (els_cmd->els_code == FC_ELS_LOGO) {
-               /**
+               /*
                 * @todo Handle LOGO frames received.
                 */
                return;
        }
 
        if (els_cmd->els_code == FC_ELS_PRLI) {
-               /**
+               /*
                 * @todo Handle PRLI frames received.
                 */
                return;
        }
 
-       /**
+       /*
         * Unhandled ELS frames. Send a LS_RJT.
         */
        bfa_fcs_lport_send_ls_rjt(lport, fchs, FC_LS_RJT_RSN_CMD_NOT_SUPP,
@@ -723,7 +715,7 @@ bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport,
 
 }
 
-/**
+/*
  *   PID based Lookup for a R-Port in the Port R-Port Queue
  */
 struct bfa_fcs_rport_s *
@@ -742,7 +734,7 @@ bfa_fcs_lport_get_rport_by_pid(struct bfa_fcs_lport_s *port, u32 pid)
        return NULL;
 }
 
-/**
+/*
  *   PWWN based Lookup for a R-Port in the Port R-Port Queue
  */
 struct bfa_fcs_rport_s *
@@ -761,7 +753,7 @@ bfa_fcs_lport_get_rport_by_pwwn(struct bfa_fcs_lport_s *port, wwn_t pwwn)
        return NULL;
 }
 
-/**
+/*
  *   NWWN based Lookup for a R-Port in the Port R-Port Queue
  */
 struct bfa_fcs_rport_s *
@@ -780,7 +772,7 @@ bfa_fcs_lport_get_rport_by_nwwn(struct bfa_fcs_lport_s *port, wwn_t nwwn)
        return NULL;
 }
 
-/**
+/*
  * Called by rport module when new rports are discovered.
  */
 void
@@ -792,7 +784,7 @@ bfa_fcs_lport_add_rport(
        port->num_rports++;
 }
 
-/**
+/*
  * Called by rport module to when rports are deleted.
  */
 void
@@ -807,7 +799,7 @@ bfa_fcs_lport_del_rport(
        bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELRPORT);
 }
 
-/**
+/*
  * Called by fabric for base port when fabric login is complete.
  * Called by vport for virtual ports when FDISC is complete.
  */
@@ -817,7 +809,7 @@ bfa_fcs_lport_online(struct bfa_fcs_lport_s *port)
        bfa_sm_send_event(port, BFA_FCS_PORT_SM_ONLINE);
 }
 
-/**
+/*
  * Called by fabric for base port when fabric goes offline.
  * Called by vport for virtual ports when virtual port becomes offline.
  */
@@ -827,7 +819,7 @@ bfa_fcs_lport_offline(struct bfa_fcs_lport_s *port)
        bfa_sm_send_event(port, BFA_FCS_PORT_SM_OFFLINE);
 }
 
-/**
+/*
  * Called by fabric to delete base lport and associated resources.
  *
  * Called by vport to delete lport and associated resources. Should call
@@ -839,7 +831,7 @@ bfa_fcs_lport_delete(struct bfa_fcs_lport_s *port)
        bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELETE);
 }
 
-/**
+/*
  * Return TRUE if port is online, else return FALSE
  */
 bfa_boolean_t
@@ -848,7 +840,7 @@ bfa_fcs_lport_is_online(struct bfa_fcs_lport_s *port)
        return bfa_sm_cmp_state(port, bfa_fcs_lport_sm_online);
 }
 
-/**
+/*
   * Attach time initialization of logical ports.
  */
 void
@@ -865,7 +857,7 @@ bfa_fcs_lport_attach(struct bfa_fcs_lport_s *lport, struct bfa_fcs_s *fcs,
        lport->num_rports = 0;
 }
 
-/**
+/*
  * Logical port initialization of base or virtual port.
  * Called by fabric for base port or by vport for virtual ports.
  */
@@ -878,7 +870,7 @@ bfa_fcs_lport_init(struct bfa_fcs_lport_s *lport,
        struct bfad_s *bfad = (struct bfad_s *)lport->fcs->bfad;
        char    lpwwn_buf[BFA_STRING_32];
 
-       bfa_os_assign(lport->port_cfg, *port_cfg);
+       lport->port_cfg = *port_cfg;
 
        lport->bfad_port = bfa_fcb_lport_new(lport->fcs->bfad, lport,
                                        lport->port_cfg.roles,
@@ -894,7 +886,7 @@ bfa_fcs_lport_init(struct bfa_fcs_lport_s *lport,
        bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE);
 }
 
-/**
+/*
  *  fcs_lport_api
  */
 
@@ -934,11 +926,11 @@ bfa_fcs_lport_get_attr(
        }
 }
 
-/**
+/*
  *  bfa_fcs_lport_fab port fab functions
  */
 
-/**
+/*
  *   Called by port to initialize fabric services of the base port.
  */
 static void
@@ -949,7 +941,7 @@ bfa_fcs_lport_fab_init(struct bfa_fcs_lport_s *port)
        bfa_fcs_lport_ms_init(port);
 }
 
-/**
+/*
  *   Called by port to notify transition to online state.
  */
 static void
@@ -959,7 +951,7 @@ bfa_fcs_lport_fab_online(struct bfa_fcs_lport_s *port)
        bfa_fcs_lport_scn_online(port);
 }
 
-/**
+/*
  *   Called by port to notify transition to offline state.
  */
 static void
@@ -970,11 +962,11 @@ bfa_fcs_lport_fab_offline(struct bfa_fcs_lport_s *port)
        bfa_fcs_lport_ms_offline(port);
 }
 
-/**
+/*
  *  bfa_fcs_lport_n2n  functions
  */
 
-/**
+/*
  *   Called by fcs/port to initialize N2N topology.
  */
 static void
@@ -982,7 +974,7 @@ bfa_fcs_lport_n2n_init(struct bfa_fcs_lport_s *port)
 {
 }
 
-/**
+/*
  *   Called by fcs/port to notify transition to online state.
  */
 static void
@@ -1006,7 +998,7 @@ bfa_fcs_lport_n2n_online(struct bfa_fcs_lport_s *port)
            ((void *)&pcfg->pwwn, (void *)&n2n_port->rem_port_wwn,
             sizeof(wwn_t)) > 0) {
                port->pid = N2N_LOCAL_PID;
-               /**
+               /*
                 * First, check if we know the device by pwwn.
                 */
                rport = bfa_fcs_lport_get_rport_by_pwwn(port,
@@ -1035,7 +1027,7 @@ bfa_fcs_lport_n2n_online(struct bfa_fcs_lport_s *port)
        }
 }
 
-/**
+/*
  *   Called by fcs/port to notify transition to offline state.
  */
 static void
@@ -1094,11 +1086,11 @@ static void     bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi,
                                 struct bfa_fcs_fdmi_hba_attr_s *hba_attr);
 static void    bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi,
                                  struct bfa_fcs_fdmi_port_attr_s *port_attr);
-/**
+/*
  *  fcs_fdmi_sm FCS FDMI state machine
  */
 
-/**
+/*
  *  FDMI State Machine events
  */
 enum port_fdmi_event {
@@ -1143,7 +1135,7 @@ static void     bfa_fcs_lport_fdmi_sm_online(struct bfa_fcs_lport_fdmi_s *fdmi,
 static void     bfa_fcs_lport_fdmi_sm_disabled(
                                struct bfa_fcs_lport_fdmi_s *fdmi,
                                enum port_fdmi_event event);
-/**
+/*
  *     Start in offline state - awaiting MS to send start.
  */
 static void
@@ -1510,7 +1502,7 @@ bfa_fcs_lport_fdmi_sm_online(struct bfa_fcs_lport_fdmi_s *fdmi,
                bfa_sm_fault(port->fcs, event);
        }
 }
-/**
+/*
  *  FDMI is disabled state.
  */
 static void
@@ -1525,7 +1517,7 @@ bfa_fcs_lport_fdmi_sm_disabled(struct bfa_fcs_lport_fdmi_s *fdmi,
        /* No op State. It can only be enabled at Driver Init. */
 }
 
-/**
+/*
 *  RHBA : Register HBA Attributes.
  */
 static void
@@ -1549,7 +1541,7 @@ bfa_fcs_lport_fdmi_send_rhba(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
        fdmi->fcxp = fcxp;
 
        pyld = bfa_fcxp_get_reqbuf(fcxp);
-       bfa_os_memset(pyld, 0, FC_MAX_PDUSZ);
+       memset(pyld, 0, FC_MAX_PDUSZ);
 
        len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port),
                                   FDMI_RHBA);
@@ -1584,7 +1576,7 @@ bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld)
        bfa_fcs_fdmi_get_hbaattr(fdmi, fcs_hba_attr);
 
        rhba->hba_id = bfa_fcs_lport_get_pwwn(port);
-       rhba->port_list.num_ports = bfa_os_htonl(1);
+       rhba->port_list.num_ports = cpu_to_be32(1);
        rhba->port_list.port_entry = bfa_fcs_lport_get_pwwn(port);
 
        len = sizeof(rhba->hba_id) + sizeof(rhba->port_list);
@@ -1601,86 +1593,69 @@ bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld)
         * Node Name
         */
        attr = (struct fdmi_attr_s *) curr_ptr;
-       attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_NODENAME);
+       attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_NODENAME);
        attr->len = sizeof(wwn_t);
        memcpy(attr->value, &bfa_fcs_lport_get_nwwn(port), attr->len);
        curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
        len += attr->len;
        count++;
-       attr->len =
-               bfa_os_htons(attr->len + sizeof(attr->type) +
+       attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
                             sizeof(attr->len));
 
        /*
         * Manufacturer
         */
        attr = (struct fdmi_attr_s *) curr_ptr;
-       attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MANUFACTURER);
+       attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MANUFACTURER);
        attr->len = (u16) strlen(fcs_hba_attr->manufacturer);
        memcpy(attr->value, fcs_hba_attr->manufacturer, attr->len);
-       attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
-                                                                *fields need
-                                                                *to be 4 byte
-                                                                *aligned */
+       attr->len = fc_roundup(attr->len, sizeof(u32));
        curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
        len += attr->len;
        count++;
-       attr->len =
-               bfa_os_htons(attr->len + sizeof(attr->type) +
+       attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
                             sizeof(attr->len));
 
        /*
         * Serial Number
         */
        attr = (struct fdmi_attr_s *) curr_ptr;
-       attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_SERIALNUM);
+       attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_SERIALNUM);
        attr->len = (u16) strlen(fcs_hba_attr->serial_num);
        memcpy(attr->value, fcs_hba_attr->serial_num, attr->len);
-       attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
-                                                                *fields need
-                                                                *to be 4 byte
-                                                                *aligned */
+       attr->len = fc_roundup(attr->len, sizeof(u32));
        curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
        len += attr->len;
        count++;
-       attr->len =
-               bfa_os_htons(attr->len + sizeof(attr->type) +
+       attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
                             sizeof(attr->len));
 
        /*
         * Model
         */
        attr = (struct fdmi_attr_s *) curr_ptr;
-       attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MODEL);
+       attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MODEL);
        attr->len = (u16) strlen(fcs_hba_attr->model);
        memcpy(attr->value, fcs_hba_attr->model, attr->len);
-       attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
-                                                                *fields need
-                                                                *to be 4 byte
-                                                                *aligned */
+       attr->len = fc_roundup(attr->len, sizeof(u32));
        curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
        len += attr->len;
        count++;
-       attr->len =
-               bfa_os_htons(attr->len + sizeof(attr->type) +
+       attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
                             sizeof(attr->len));
 
        /*
         * Model Desc
         */
        attr = (struct fdmi_attr_s *) curr_ptr;
-       attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MODEL_DESC);
+       attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MODEL_DESC);
        attr->len = (u16) strlen(fcs_hba_attr->model_desc);
        memcpy(attr->value, fcs_hba_attr->model_desc, attr->len);
-       attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
-                                                        *fields need
-                                                        *to be 4 byte
-                                                        *aligned */
+       attr->len = fc_roundup(attr->len, sizeof(u32));
        curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
        len += attr->len;
        count++;
-       attr->len =
-               bfa_os_htons(attr->len + sizeof(attr->type) +
+       attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
                             sizeof(attr->len));
 
        /*
@@ -1688,18 +1663,14 @@ bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld)
         */
        if (fcs_hba_attr->hw_version[0] != '\0') {
                attr = (struct fdmi_attr_s *) curr_ptr;
-               attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_HW_VERSION);
+               attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_HW_VERSION);
                attr->len = (u16) strlen(fcs_hba_attr->hw_version);
                memcpy(attr->value, fcs_hba_attr->hw_version, attr->len);
-               attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
-                                                                *fields need
-                                                                *to be 4 byte
-                                                                *aligned */
+               attr->len = fc_roundup(attr->len, sizeof(u32));
                curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
                len += attr->len;
                count++;
-               attr->len =
-                       bfa_os_htons(attr->len + sizeof(attr->type) +
+               attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
                                         sizeof(attr->len));
        }
 
@@ -1707,18 +1678,14 @@ bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld)
         * Driver Version
         */
        attr = (struct fdmi_attr_s *) curr_ptr;
-       attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_DRIVER_VERSION);
+       attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_DRIVER_VERSION);
        attr->len = (u16) strlen(fcs_hba_attr->driver_version);
        memcpy(attr->value, fcs_hba_attr->driver_version, attr->len);
-       attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
-                                                        *fields need
-                                                        *to be 4 byte
-                                                        *aligned */
+       attr->len = fc_roundup(attr->len, sizeof(u32));
        curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
        len += attr->len;;
        count++;
-       attr->len =
-               bfa_os_htons(attr->len + sizeof(attr->type) +
+       attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
                             sizeof(attr->len));
 
        /*
@@ -1726,18 +1693,14 @@ bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld)
         */
        if (fcs_hba_attr->option_rom_ver[0] != '\0') {
                attr = (struct fdmi_attr_s *) curr_ptr;
-               attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_ROM_VERSION);
+               attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_ROM_VERSION);
                attr->len = (u16) strlen(fcs_hba_attr->option_rom_ver);
                memcpy(attr->value, fcs_hba_attr->option_rom_ver, attr->len);
-               attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
-                                                                *fields need
-                                                                *to be 4 byte
-                                                                *aligned */
+               attr->len = fc_roundup(attr->len, sizeof(u32));
                curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
                len += attr->len;
                count++;
-               attr->len =
-                       bfa_os_htons(attr->len + sizeof(attr->type) +
+               attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
                                         sizeof(attr->len));
        }
 
@@ -1745,18 +1708,14 @@ bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld)
         * f/w Version = driver version
         */
        attr = (struct fdmi_attr_s *) curr_ptr;
-       attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_FW_VERSION);
+       attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_FW_VERSION);
        attr->len = (u16) strlen(fcs_hba_attr->driver_version);
        memcpy(attr->value, fcs_hba_attr->driver_version, attr->len);
-       attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
-                                                        *fields need
-                                                        *to be 4 byte
-                                                        *aligned */
+       attr->len = fc_roundup(attr->len, sizeof(u32));
        curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
        len += attr->len;
        count++;
-       attr->len =
-               bfa_os_htons(attr->len + sizeof(attr->type) +
+       attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
                             sizeof(attr->len));
 
        /*
@@ -1764,18 +1723,14 @@ bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld)
         */
        if (fcs_hba_attr->os_name[0] != '\0') {
                attr = (struct fdmi_attr_s *) curr_ptr;
-               attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_OS_NAME);
+               attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_OS_NAME);
                attr->len = (u16) strlen(fcs_hba_attr->os_name);
                memcpy(attr->value, fcs_hba_attr->os_name, attr->len);
-               attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
-                                                            *fields need
-                                                            *to be 4 byte
-                                                            *aligned */
+               attr->len = fc_roundup(attr->len, sizeof(u32));
                curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
                len += attr->len;
                count++;
-               attr->len =
-                       bfa_os_htons(attr->len + sizeof(attr->type) +
+               attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
                                        sizeof(attr->len));
        }
 
@@ -1783,22 +1738,20 @@ bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld)
         * MAX_CT_PAYLOAD
         */
        attr = (struct fdmi_attr_s *) curr_ptr;
-       attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MAX_CT);
+       attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MAX_CT);
        attr->len = sizeof(fcs_hba_attr->max_ct_pyld);
        memcpy(attr->value, &fcs_hba_attr->max_ct_pyld, attr->len);
        len += attr->len;
        count++;
-       attr->len =
-               bfa_os_htons(attr->len + sizeof(attr->type) +
+       attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
                             sizeof(attr->len));
 
        /*
         * Update size of payload
         */
-       len += ((sizeof(attr->type) +
-                sizeof(attr->len)) * count);
+       len += ((sizeof(attr->type) + sizeof(attr->len)) * count);
 
-       rhba->hba_attr_blk.attr_count = bfa_os_htonl(count);
+       rhba->hba_attr_blk.attr_count = cpu_to_be32(count);
        return len;
 }
 
@@ -1825,7 +1778,7 @@ bfa_fcs_lport_fdmi_rhba_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        }
 
        cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
-       cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+       cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
 
        if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
                bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK);
@@ -1837,7 +1790,7 @@ bfa_fcs_lport_fdmi_rhba_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
 }
 
-/**
+/*
 *  RPRT : Register Port
  */
 static void
@@ -1861,7 +1814,7 @@ bfa_fcs_lport_fdmi_send_rprt(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
        fdmi->fcxp = fcxp;
 
        pyld = bfa_fcxp_get_reqbuf(fcxp);
-       bfa_os_memset(pyld, 0, FC_MAX_PDUSZ);
+       memset(pyld, 0, FC_MAX_PDUSZ);
 
        len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port),
                                   FDMI_RPRT);
@@ -1879,7 +1832,7 @@ bfa_fcs_lport_fdmi_send_rprt(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
        bfa_sm_send_event(fdmi, FDMISM_EVENT_RPRT_SENT);
 }
 
-/**
+/*
  * This routine builds Port Attribute Block that used in RPA, RPRT commands.
  */
 static          u16
@@ -1909,56 +1862,54 @@ bfa_fcs_lport_fdmi_build_portattr_block(struct bfa_fcs_lport_fdmi_s *fdmi,
         * FC4 Types
         */
        attr = (struct fdmi_attr_s *) curr_ptr;
-       attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_FC4_TYPES);
+       attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_FC4_TYPES);
        attr->len = sizeof(fcs_port_attr.supp_fc4_types);
        memcpy(attr->value, fcs_port_attr.supp_fc4_types, attr->len);
        curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
        len += attr->len;
        ++count;
        attr->len =
-               bfa_os_htons(attr->len + sizeof(attr->type) +
+               cpu_to_be16(attr->len + sizeof(attr->type) +
                             sizeof(attr->len));
 
        /*
         * Supported Speed
         */
        attr = (struct fdmi_attr_s *) curr_ptr;
-       attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_SUPP_SPEED);
+       attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_SUPP_SPEED);
        attr->len = sizeof(fcs_port_attr.supp_speed);
        memcpy(attr->value, &fcs_port_attr.supp_speed, attr->len);
        curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
        len += attr->len;
        ++count;
        attr->len =
-               bfa_os_htons(attr->len + sizeof(attr->type) +
+               cpu_to_be16(attr->len + sizeof(attr->type) +
                             sizeof(attr->len));
 
        /*
         * current Port Speed
         */
        attr = (struct fdmi_attr_s *) curr_ptr;
-       attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_PORT_SPEED);
+       attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_PORT_SPEED);
        attr->len = sizeof(fcs_port_attr.curr_speed);
        memcpy(attr->value, &fcs_port_attr.curr_speed, attr->len);
        curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
        len += attr->len;
        ++count;
-       attr->len =
-               bfa_os_htons(attr->len + sizeof(attr->type) +
+       attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
                             sizeof(attr->len));
 
        /*
         * max frame size
         */
        attr = (struct fdmi_attr_s *) curr_ptr;
-       attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_FRAME_SIZE);
+       attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_FRAME_SIZE);
        attr->len = sizeof(fcs_port_attr.max_frm_size);
        memcpy(attr->value, &fcs_port_attr.max_frm_size, attr->len);
        curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
        len += attr->len;
        ++count;
-       attr->len =
-               bfa_os_htons(attr->len + sizeof(attr->type) +
+       attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
                             sizeof(attr->len));
 
        /*
@@ -1966,18 +1917,14 @@ bfa_fcs_lport_fdmi_build_portattr_block(struct bfa_fcs_lport_fdmi_s *fdmi,
         */
        if (fcs_port_attr.os_device_name[0] != '\0') {
                attr = (struct fdmi_attr_s *) curr_ptr;
-               attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_DEV_NAME);
+               attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_DEV_NAME);
                attr->len = (u16) strlen(fcs_port_attr.os_device_name);
                memcpy(attr->value, fcs_port_attr.os_device_name, attr->len);
-               attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
-                                                            *fields need
-                                                            *to be 4 byte
-                                                            *aligned */
+               attr->len = fc_roundup(attr->len, sizeof(u32));
                curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
                len += attr->len;
                ++count;
-               attr->len =
-                       bfa_os_htons(attr->len + sizeof(attr->type) +
+               attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
                                        sizeof(attr->len));
        }
        /*
@@ -1985,27 +1932,22 @@ bfa_fcs_lport_fdmi_build_portattr_block(struct bfa_fcs_lport_fdmi_s *fdmi,
         */
        if (fcs_port_attr.host_name[0] != '\0') {
                attr = (struct fdmi_attr_s *) curr_ptr;
-               attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_HOST_NAME);
+               attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_HOST_NAME);
                attr->len = (u16) strlen(fcs_port_attr.host_name);
                memcpy(attr->value, fcs_port_attr.host_name, attr->len);
-               attr->len = fc_roundup(attr->len, sizeof(u32)); /* variable
-                                                            *fields need
-                                                            *to be 4 byte
-                                                            *aligned */
+               attr->len = fc_roundup(attr->len, sizeof(u32));
                curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
                len += attr->len;
                ++count;
-               attr->len =
-                       bfa_os_htons(attr->len + sizeof(attr->type) +
+               attr->len = cpu_to_be16(attr->len + sizeof(attr->type) +
                                sizeof(attr->len));
        }
 
        /*
         * Update size of payload
         */
-       port_attrib->attr_count = bfa_os_htonl(count);
-       len += ((sizeof(attr->type) +
-                sizeof(attr->len)) * count);
+       port_attrib->attr_count = cpu_to_be32(count);
+       len += ((sizeof(attr->type) + sizeof(attr->len)) * count);
        return len;
 }
 
@@ -2050,7 +1992,7 @@ bfa_fcs_lport_fdmi_rprt_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        }
 
        cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
-       cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+       cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
 
        if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
                bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK);
@@ -2062,7 +2004,7 @@ bfa_fcs_lport_fdmi_rprt_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
 }
 
-/**
+/*
 *  RPA : Register Port Attributes.
  */
 static void
@@ -2086,15 +2028,13 @@ bfa_fcs_lport_fdmi_send_rpa(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
        fdmi->fcxp = fcxp;
 
        pyld = bfa_fcxp_get_reqbuf(fcxp);
-       bfa_os_memset(pyld, 0, FC_MAX_PDUSZ);
+       memset(pyld, 0, FC_MAX_PDUSZ);
 
        len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port),
                                   FDMI_RPA);
 
-       attr_len =
-               bfa_fcs_lport_fdmi_build_rpa_pyld(fdmi,
-                                        (u8 *) ((struct ct_hdr_s *) pyld
-                                                     + 1));
+       attr_len = bfa_fcs_lport_fdmi_build_rpa_pyld(fdmi,
+                               (u8 *) ((struct ct_hdr_s *) pyld + 1));
 
        bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
                          FC_CLASS_3, len + attr_len, &fchs,
@@ -2143,7 +2083,7 @@ bfa_fcs_lport_fdmi_rpa_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        }
 
        cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
-       cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+       cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
 
        if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
                bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK);
@@ -2170,7 +2110,7 @@ bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi,
        struct bfa_fcs_lport_s *port = fdmi->ms->port;
        struct bfa_fcs_driver_info_s  *driver_info = &port->fcs->driver_info;
 
-       bfa_os_memset(hba_attr, 0, sizeof(struct bfa_fcs_fdmi_hba_attr_s));
+       memset(hba_attr, 0, sizeof(struct bfa_fcs_fdmi_hba_attr_s));
 
        bfa_ioc_get_adapter_manufacturer(&port->fcs->bfa->ioc,
                                        hba_attr->manufacturer);
@@ -2204,7 +2144,7 @@ bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi,
                                sizeof(driver_info->host_os_patch));
        }
 
-       hba_attr->max_ct_pyld = bfa_os_htonl(FC_MAX_PDUSZ);
+       hba_attr->max_ct_pyld = cpu_to_be32(FC_MAX_PDUSZ);
 }
 
 void
@@ -2215,7 +2155,7 @@ bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi,
        struct bfa_fcs_driver_info_s  *driver_info = &port->fcs->driver_info;
        struct bfa_port_attr_s pport_attr;
 
-       bfa_os_memset(port_attr, 0, sizeof(struct bfa_fcs_fdmi_port_attr_s));
+       memset(port_attr, 0, sizeof(struct bfa_fcs_fdmi_port_attr_s));
 
        /*
         * get pport attributes from hal
@@ -2230,17 +2170,17 @@ bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi,
        /*
         * Supported Speeds
         */
-       port_attr->supp_speed = bfa_os_htonl(BFA_FCS_FDMI_SUPORTED_SPEEDS);
+       port_attr->supp_speed = cpu_to_be32(BFA_FCS_FDMI_SUPORTED_SPEEDS);
 
        /*
         * Current Speed
         */
-       port_attr->curr_speed = bfa_os_htonl(pport_attr.speed);
+       port_attr->curr_speed = cpu_to_be32(pport_attr.speed);
 
        /*
         * Max PDU Size.
         */
-       port_attr->max_frm_size = bfa_os_htonl(FC_MAX_PDUSZ);
+       port_attr->max_frm_size = cpu_to_be32(FC_MAX_PDUSZ);
 
        /*
         * OS device Name
@@ -2321,11 +2261,11 @@ static void     bfa_fcs_lport_ms_gfn_response(void *fcsarg,
                                               u32 rsp_len,
                                               u32 resid_len,
                                               struct fchs_s *rsp_fchs);
-/**
+/*
  *  fcs_ms_sm FCS MS state machine
  */
 
-/**
+/*
  *  MS State Machine events
  */
 enum port_ms_event {
@@ -2360,7 +2300,7 @@ static void     bfa_fcs_lport_ms_sm_gfn_retry(struct bfa_fcs_lport_ms_s *ms,
                                               enum port_ms_event event);
 static void     bfa_fcs_lport_ms_sm_online(struct bfa_fcs_lport_ms_s *ms,
                                          enum port_ms_event event);
-/**
+/*
  *     Start in offline state - awaiting NS to send start.
  */
 static void
@@ -2432,7 +2372,7 @@ bfa_fcs_lport_ms_sm_plogi(struct bfa_fcs_lport_ms_s *ms,
                 */
                bfa_fcs_lport_fdmi_online(ms);
 
-               /**
+               /*
                 * if this is a Vport, go to online state.
                 */
                if (ms->port->vport) {
@@ -2595,7 +2535,7 @@ bfa_fcs_lport_ms_sm_gmal_retry(struct bfa_fcs_lport_ms_s *ms,
                bfa_sm_fault(ms->port->fcs, event);
        }
 }
-/**
+/*
  *  ms_pvt MS local functions
  */
 
@@ -2657,12 +2597,12 @@ bfa_fcs_lport_ms_gmal_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        }
 
        cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
-       cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+       cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
 
        if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
                gmal_resp = (struct fcgs_gmal_resp_s *)(cthdr + 1);
 
-               num_entries = bfa_os_ntohl(gmal_resp->ms_len);
+               num_entries = be32_to_cpu(gmal_resp->ms_len);
                if (num_entries == 0) {
                        bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
                        return;
@@ -2795,7 +2735,7 @@ bfa_fcs_lport_ms_sm_gfn_retry(struct bfa_fcs_lport_ms_s *ms,
                bfa_sm_fault(ms->port->fcs, event);
        }
 }
-/**
+/*
  *  ms_pvt MS local functions
  */
 
@@ -2853,7 +2793,7 @@ bfa_fcs_lport_ms_gfn_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        }
 
        cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
-       cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+       cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
 
        if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
                gfn_resp = (wwn_t *)(cthdr + 1);
@@ -2871,7 +2811,7 @@ bfa_fcs_lport_ms_gfn_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
 }
 
-/**
+/*
  *  ms_pvt MS local functions
  */
 
@@ -3017,7 +2957,7 @@ bfa_fcs_lport_ms_fabric_rscn(struct bfa_fcs_lport_s *port)
                bfa_sm_send_event(ms, MSSM_EVENT_PORT_FABRIC_RSCN);
 }
 
-/**
+/*
  * @page ns_sm_info VPORT NS State Machine
  *
  * @section ns_sm_interactions VPORT NS State Machine Interactions
@@ -3080,11 +3020,11 @@ static void     bfa_fcs_lport_ns_process_gidft_pids(
                                u32 *pid_buf, u32 n_pids);
 
 static void bfa_fcs_lport_ns_boot_target_disc(bfa_fcs_lport_t *port);
-/**
+/*
  *  fcs_ns_sm FCS nameserver interface state machine
  */
 
-/**
+/*
  * VPort NS State Machine events
  */
 enum vport_ns_event {
@@ -3139,7 +3079,7 @@ static void     bfa_fcs_lport_ns_sm_gid_ft_retry(struct bfa_fcs_lport_ns_s *ns,
                                                enum vport_ns_event event);
 static void     bfa_fcs_lport_ns_sm_online(struct bfa_fcs_lport_ns_s *ns,
                                          enum vport_ns_event event);
-/**
+/*
  *     Start in offline state - awaiting linkup
  */
 static void
@@ -3628,7 +3568,7 @@ bfa_fcs_lport_ns_sm_online(struct bfa_fcs_lport_ns_s *ns,
 
 
 
-/**
+/*
  *  ns_pvt Nameserver local functions
  */
 
@@ -3724,7 +3664,7 @@ bfa_fcs_lport_ns_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        }
 }
 
-/**
+/*
  * Register the symbolic port name.
  */
 static void
@@ -3738,7 +3678,7 @@ bfa_fcs_lport_ns_send_rspn_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
        u8         symbl[256];
        u8         *psymbl = &symbl[0];
 
-       bfa_os_memset(symbl, 0, sizeof(symbl));
+       memset(symbl, 0, sizeof(symbl));
 
        bfa_trc(port->fcs, port->port_cfg.pwwn);
 
@@ -3755,7 +3695,7 @@ bfa_fcs_lport_ns_send_rspn_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
         * for V-Port, form a Port Symbolic Name
         */
        if (port->vport) {
-               /**
+               /*
                 * For Vports, we append the vport's port symbolic name
                 * to that of the base port.
                 */
@@ -3815,7 +3755,7 @@ bfa_fcs_lport_ns_rspn_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        }
 
        cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
-       cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+       cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
 
        if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
                port->stats.ns_rspnid_accepts++;
@@ -3829,7 +3769,7 @@ bfa_fcs_lport_ns_rspn_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
 }
 
-/**
+/*
  * Register FC4-Types
  */
 static void
@@ -3887,7 +3827,7 @@ bfa_fcs_lport_ns_rft_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        }
 
        cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
-       cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+       cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
 
        if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
                port->stats.ns_rftid_accepts++;
@@ -3901,7 +3841,7 @@ bfa_fcs_lport_ns_rft_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
 }
 
-/**
+/*
  * Register FC4-Features : Should be done after RFT_ID
  */
 static void
@@ -3964,7 +3904,7 @@ bfa_fcs_lport_ns_rff_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        }
 
        cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
-       cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+       cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
 
        if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
                port->stats.ns_rffid_accepts++;
@@ -3982,7 +3922,7 @@ bfa_fcs_lport_ns_rff_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        } else
                bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
 }
-/**
+/*
  * Query Fabric for FC4-Types Devices.
  *
 * TBD : Need to use a local (FCS private) response buffer, since the response
@@ -4058,7 +3998,7 @@ bfa_fcs_lport_ns_gid_ft_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        }
 
        cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
-       cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+       cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
 
        switch (cthdr->cmd_rsp_code) {
 
@@ -4102,7 +4042,7 @@ bfa_fcs_lport_ns_gid_ft_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
        }
 }
 
-/**
+/*
  *     This routine will be called by bfa_timer on timer timeouts.
  *
  *     param[in]       port - pointer to bfa_fcs_lport_t.
@@ -4166,7 +4106,7 @@ bfa_fcs_lport_ns_process_gidft_pids(struct bfa_fcs_lport_s *port, u32 *pid_buf,
        }
 }
 
-/**
+/*
  *  fcs_ns_public FCS nameserver public interfaces
  */
 
@@ -4227,7 +4167,7 @@ bfa_fcs_lport_ns_boot_target_disc(bfa_fcs_lport_t *port)
        }
 }
 
-/**
+/*
  * FCS SCN
  */
 
@@ -4250,11 +4190,11 @@ static void     bfa_fcs_lport_scn_send_ls_acc(struct bfa_fcs_lport_s *port,
                                             struct fchs_s *rx_fchs);
 static void     bfa_fcs_lport_scn_timeout(void *arg);
 
-/**
+/*
  *  fcs_scm_sm FCS SCN state machine
  */
 
-/**
+/*
  * VPort SCN State Machine events
  */
 enum port_scn_event {
@@ -4278,7 +4218,7 @@ static void     bfa_fcs_lport_scn_sm_scr_retry(struct bfa_fcs_lport_scn_s *scn,
 static void     bfa_fcs_lport_scn_sm_online(struct bfa_fcs_lport_scn_s *scn,
                                           enum port_scn_event event);
 
-/**
+/*
  *     Starting state - awaiting link up.
  */
 static void
@@ -4382,11 +4322,11 @@ bfa_fcs_lport_scn_sm_online(struct bfa_fcs_lport_scn_s *scn,
 
 
 
-/**
+/*
  *  fcs_scn_private FCS SCN private functions
  */
 
-/**
+/*
  * This routine will be called to send a SCR command.
  */
 static void
@@ -4499,7 +4439,7 @@ bfa_fcs_lport_scn_send_ls_acc(struct bfa_fcs_lport_s *port,
                          FC_MAX_PDUSZ, 0);
 }
 
-/**
+/*
  *     This routine will be called by bfa_timer on timer timeouts.
  *
  *     param[in]       vport           - pointer to bfa_fcs_lport_t.
@@ -4522,7 +4462,7 @@ bfa_fcs_lport_scn_timeout(void *arg)
 
 
 
-/**
+/*
  *  fcs_scn_public FCS state change notification public interfaces
  */
 
@@ -4563,7 +4503,7 @@ bfa_fcs_lport_scn_portid_rscn(struct bfa_fcs_lport_s *port, u32 rpid)
 
        bfa_trc(port->fcs, rpid);
 
-       /**
+       /*
         * If this is an unknown device, then it just came online.
         * Otherwise let rport handle the RSCN event.
         */
@@ -4579,7 +4519,7 @@ bfa_fcs_lport_scn_portid_rscn(struct bfa_fcs_lport_s *port, u32 rpid)
                bfa_fcs_rport_scn(rport);
 }
 
-/**
+/*
  * rscn format based PID comparison
  */
 #define __fc_pid_match(__c0, __c1, __fmt)              \
@@ -4624,7 +4564,7 @@ bfa_fcs_lport_scn_process_rscn(struct bfa_fcs_lport_s *port,
        int             i = 0, j;
 
        num_entries =
-               (bfa_os_ntohs(rscn->payldlen) -
+               (be16_to_cpu(rscn->payldlen) -
                 sizeof(u32)) / sizeof(rscn->event[0]);
 
        bfa_trc(port->fcs, num_entries);
@@ -4691,18 +4631,18 @@ bfa_fcs_lport_scn_process_rscn(struct bfa_fcs_lport_s *port,
                }
        }
 
-       /**
-        * If any of area, domain or fabric RSCN is received, do a fresh discovery
-        * to find new devices.
+       /*
+        * If any of area, domain or fabric RSCN is received, do a fresh
+        * discovery to find new devices.
         */
        if (nsquery)
                bfa_fcs_lport_ns_query(port);
 }
 
-/**
+/*
  * BFA FCS port
  */
-/**
+/*
  *  fcs_port_api BFA FCS port API
  */
 struct bfa_fcs_lport_s *
@@ -4943,10 +4883,10 @@ bfa_fcs_lport_get_stats(struct bfa_fcs_lport_s *fcs_port,
 void
 bfa_fcs_lport_clear_stats(struct bfa_fcs_lport_s *fcs_port)
 {
-       bfa_os_memset(&fcs_port->stats, 0, sizeof(struct bfa_lport_stats_s));
+       memset(&fcs_port->stats, 0, sizeof(struct bfa_lport_stats_s));
 }
 
-/**
+/*
  * FCS virtual port state machine
  */
 
@@ -4967,11 +4907,11 @@ static void     bfa_fcs_vport_timeout(void *vport_arg);
 static void     bfa_fcs_vport_do_logo(struct bfa_fcs_vport_s *vport);
 static void     bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport);
 
-/**
+/*
  *  fcs_vport_sm FCS virtual port state machine
  */
 
-/**
+/*
  * VPort State Machine events
  */
 enum bfa_fcs_vport_event {
@@ -5024,7 +4964,7 @@ static struct bfa_sm_table_s  vport_sm_table[] = {
        {BFA_SM(bfa_fcs_vport_sm_error), BFA_FCS_VPORT_ERROR}
 };
 
-/**
+/*
  * Beginning state.
  */
 static void
@@ -5045,7 +4985,7 @@ bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport,
        }
 }
 
-/**
+/*
  * Created state - a start event is required to start up the state machine.
  */
 static void
@@ -5062,7 +5002,7 @@ bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport,
                        bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc);
                        bfa_fcs_vport_do_fdisc(vport);
                } else {
-                       /**
+                       /*
                         * Fabric is offline or not NPIV capable, stay in
                         * offline state.
                         */
@@ -5078,7 +5018,7 @@ bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport,
 
        case BFA_FCS_VPORT_SM_ONLINE:
        case BFA_FCS_VPORT_SM_OFFLINE:
-               /**
+               /*
                 * Ignore ONLINE/OFFLINE events from fabric
                 * till vport is started.
                 */
@@ -5089,7 +5029,7 @@ bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport,
        }
 }
 
-/**
+/*
  * Offline state - awaiting ONLINE event from fabric SM.
  */
 static void
@@ -5127,7 +5067,7 @@ bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport,
 }
 
 
-/**
+/*
  * FDISC is sent and awaiting reply from fabric.
  */
 static void
@@ -5174,7 +5114,7 @@ bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport,
        }
 }
 
-/**
+/*
  * FDISC attempt failed - a timer is active to retry FDISC.
  */
 static void
@@ -5208,7 +5148,7 @@ bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport,
        }
 }
 
-/**
+/*
  * Vport is online (FDISC is complete).
  */
 static void
@@ -5235,7 +5175,7 @@ bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport,
        }
 }
 
-/**
+/*
  * Vport is being deleted - awaiting lport delete completion to send
  * LOGO to fabric.
  */
@@ -5264,7 +5204,7 @@ bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport,
        }
 }
 
-/**
+/*
  * Error State.
  * This state will be set when the Vport Creation fails due
  * to errors like Dup WWN. In this state only operation allowed
@@ -5288,7 +5228,7 @@ bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport,
        }
 }
 
-/**
+/*
  * Lport cleanup is in progress since vport is being deleted. Fabric is
  * offline, so no LOGO is needed to complete vport deletion.
  */
@@ -5313,7 +5253,7 @@ bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport,
        }
 }
 
-/**
+/*
  * LOGO is sent to fabric. Vport delete is in progress. Lport delete cleanup
  * is done.
  */
@@ -5347,10 +5287,10 @@ bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport,
 
 
 
-/**
+/*
  *  fcs_vport_private FCS virtual port private functions
  */
-/**
+/*
  * This routine will be called to send a FDISC command.
  */
 static void
@@ -5397,7 +5337,7 @@ bfa_fcs_vport_fdisc_rejected(struct bfa_fcs_vport_s *vport)
        }
 }
 
-/**
+/*
  *     Called to send a logout to the fabric. Used when a V-Port is
  *     deleted/stopped.
  */
@@ -5411,7 +5351,7 @@ bfa_fcs_vport_do_logo(struct bfa_fcs_vport_s *vport)
 }
 
 
-/**
+/*
  *     This routine will be called by bfa_timer on timer timeouts.
  *
  *     param[in]       vport           - pointer to bfa_fcs_vport_t.
@@ -5449,11 +5389,11 @@ bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport)
 
 
 
-/**
+/*
  *  fcs_vport_public FCS virtual port public interfaces
  */
 
-/**
+/*
  * Online notification from fabric SM.
  */
 void
@@ -5463,7 +5403,7 @@ bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport)
        bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE);
 }
 
-/**
+/*
  * Offline notification from fabric SM.
  */
 void
@@ -5473,7 +5413,7 @@ bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport)
        bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_OFFLINE);
 }
 
-/**
+/*
  * Cleanup notification from fabric SM on link timer expiry.
  */
 void
@@ -5481,7 +5421,7 @@ bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport)
 {
        vport->vport_stats.fab_cleanup++;
 }
-/**
+/*
  * delete notification from fabric SM. To be invoked from within FCS.
  */
 void
@@ -5490,7 +5430,7 @@ bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport)
        bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELETE);
 }
 
-/**
+/*
  * Delete completion callback from associated lport
  */
 void
@@ -5501,11 +5441,11 @@ bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport)
 
 
 
-/**
+/*
  *  fcs_vport_api Virtual port API
  */
 
-/**
+/*
  *     Use this function to instantiate a new FCS vport object. This
  *     function will not trigger any HW initialization process (which will be
  *     done in vport_start() call)
@@ -5555,7 +5495,7 @@ bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs,
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  *     Use this function to instantiate a new FCS PBC vport object. This
  *     function will not trigger any HW initialization process (which will be
  *     done in vport_start() call)
@@ -5585,7 +5525,7 @@ bfa_fcs_pbc_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs,
        return rc;
 }
 
-/**
+/*
  *     Use this function to findout if this is a pbc vport or not.
  *
  * @param[in] vport - pointer to bfa_fcs_vport_t.
@@ -5603,7 +5543,7 @@ bfa_fcs_is_pbc_vport(struct bfa_fcs_vport_s *vport)
 
 }
 
-/**
+/*
  * Use this function initialize the vport.
  *
  * @param[in] vport - pointer to bfa_fcs_vport_t.
@@ -5618,7 +5558,7 @@ bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport)
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  *     Use this function quiese the vport object. This function will return
  *     immediately, when the vport is actually stopped, the
  *     bfa_drv_vport_stop_cb() will be called.
@@ -5635,7 +5575,7 @@ bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport)
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  *     Use this function to delete a vport object. Fabric object should
  *     be stopped before this function call.
  *
@@ -5657,7 +5597,7 @@ bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport)
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  *     Use this function to get vport's current status info.
  *
  *     param[in] vport         pointer to bfa_fcs_vport_t.
@@ -5672,13 +5612,13 @@ bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport,
        if (vport == NULL || attr == NULL)
                return;
 
-       bfa_os_memset(attr, 0, sizeof(struct bfa_vport_attr_s));
+       memset(attr, 0, sizeof(struct bfa_vport_attr_s));
 
        bfa_fcs_lport_get_attr(&vport->lport, &attr->port_attr);
        attr->vport_state = bfa_sm_to_state(vport_sm_table, vport->sm);
 }
 
-/**
+/*
  *     Use this function to get vport's statistics.
  *
  *     param[in]       vport   pointer to bfa_fcs_vport_t.
@@ -5693,7 +5633,7 @@ bfa_fcs_vport_get_stats(struct bfa_fcs_vport_s *vport,
        *stats = vport->vport_stats;
 }
 
-/**
+/*
  *     Use this function to clear vport's statistics.
  *
  *     param[in]       vport   pointer to bfa_fcs_vport_t.
@@ -5703,10 +5643,10 @@ bfa_fcs_vport_get_stats(struct bfa_fcs_vport_s *vport,
 void
 bfa_fcs_vport_clr_stats(struct bfa_fcs_vport_s *vport)
 {
-       bfa_os_memset(&vport->vport_stats, 0, sizeof(struct bfa_vport_stats_s));
+       memset(&vport->vport_stats, 0, sizeof(struct bfa_vport_stats_s));
 }
 
-/**
+/*
  *     Lookup a virtual port. Excludes base port from lookup.
  */
 struct bfa_fcs_vport_s *
@@ -5728,7 +5668,7 @@ bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t vpwwn)
        return vport;
 }
 
-/**
+/*
  * FDISC Response
  */
 void
@@ -5784,7 +5724,7 @@ bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status)
        }
 }
 
-/**
+/*
  * LOGO response
  */
 void
@@ -5794,7 +5734,7 @@ bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg)
        bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK);
 }
 
-/**
+/*
  * Received clear virtual link
  */
 void
index 635f0cd887145deeb96b2f24914a8622269b3319..47f35c0ef29a0c69f5d6842a6db0d173a0195e84 100644 (file)
@@ -15,7 +15,7 @@
  * General Public License for more details.
  */
 
-/**
+/*
  *  rport.c Remote port implementation.
  */
 
@@ -75,7 +75,7 @@ static void   bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport,
 static void    bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport,
                                struct fchs_s *rx_fchs, u16 len);
 static void bfa_fcs_rport_send_prlo_acc(struct bfa_fcs_rport_s *rport);
-/**
+/*
  *  fcs_rport_sm FCS rport state machine events
  */
 
@@ -172,7 +172,7 @@ static struct bfa_sm_table_s rport_sm_table[] = {
        {BFA_SM(bfa_fcs_rport_sm_nsdisc_sent), BFA_RPORT_NSDISC},
 };
 
-/**
+/*
  *             Beginning state.
  */
 static void
@@ -210,7 +210,7 @@ bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport, enum rport_event event)
        }
 }
 
-/**
+/*
  *             PLOGI is being sent.
  */
 static void
@@ -262,7 +262,7 @@ bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport,
        }
 }
 
-/**
+/*
  *             PLOGI is being sent.
  */
 static void
@@ -287,7 +287,7 @@ bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport,
 
        case RPSM_EVENT_PLOGI_RCVD:
        case RPSM_EVENT_SCN:
-               /**
+               /*
                 * Ignore, SCN is possibly online notification.
                 */
                break;
@@ -309,7 +309,7 @@ bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport,
                break;
 
        case RPSM_EVENT_HCB_OFFLINE:
-               /**
+               /*
                 * Ignore BFA callback, on a PLOGI receive we call bfa offline.
                 */
                break;
@@ -319,7 +319,7 @@ bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport,
        }
 }
 
-/**
+/*
  *             PLOGI is sent.
  */
 static void
@@ -380,7 +380,7 @@ bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport,
        }
 }
 
-/**
+/*
  *             PLOGI is sent.
  */
 static void
@@ -475,7 +475,7 @@ bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event)
        }
 }
 
-/**
+/*
  *             PLOGI is complete. Awaiting BFA rport online callback. FC-4s
  *             are offline.
  */
@@ -519,7 +519,7 @@ bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport,
                break;
 
        case RPSM_EVENT_SCN:
-               /**
+               /*
                 * @todo
                 * Ignore SCN - PLOGI just completed, FC-4 login should detect
                 * device failures.
@@ -531,7 +531,7 @@ bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport,
        }
 }
 
-/**
+/*
  *             Rport is ONLINE. FC-4s active.
  */
 static void
@@ -580,7 +580,7 @@ bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, enum rport_event event)
        }
 }
 
-/**
+/*
  *             An SCN event is received in ONLINE state. NS query is being sent
  *             prior to ADISC authentication with rport. FC-4s are paused.
  */
@@ -604,7 +604,7 @@ bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport,
                break;
 
        case RPSM_EVENT_SCN:
-               /**
+               /*
                 * ignore SCN, wait for response to query itself
                 */
                break;
@@ -638,7 +638,7 @@ bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport,
        }
 }
 
-/**
+/*
  *     An SCN event is received in ONLINE state. NS query is sent to rport.
  *     FC-4s are paused.
  */
@@ -697,7 +697,7 @@ bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event)
        }
 }
 
-/**
+/*
  *     An SCN event is received in ONLINE state. ADISC is being sent for
  *     authenticating with rport. FC-4s are paused.
  */
@@ -748,7 +748,7 @@ bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport,
        }
 }
 
-/**
+/*
  *             An SCN event is received in ONLINE state. ADISC is to rport.
  *             FC-4s are paused.
  */
@@ -765,7 +765,7 @@ bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event)
                break;
 
        case RPSM_EVENT_PLOGI_RCVD:
-               /**
+               /*
                 * Too complex to cleanup FC-4 & rport and then acc to PLOGI.
                 * At least go offline when a PLOGI is received.
                 */
@@ -787,7 +787,7 @@ bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event)
                break;
 
        case RPSM_EVENT_SCN:
-               /**
+               /*
                 * already processing RSCN
                 */
                break;
@@ -810,7 +810,7 @@ bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event)
        }
 }
 
-/**
+/*
  *             Rport has sent LOGO. Awaiting FC-4 offline completion callback.
  */
 static void
@@ -841,7 +841,7 @@ bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport,
        }
 }
 
-/**
+/*
  *             LOGO needs to be sent to rport. Awaiting FC-4 offline completion
  *             callback.
  */
@@ -864,7 +864,7 @@ bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport,
        }
 }
 
-/**
+/*
  *     Rport is going offline. Awaiting FC-4 offline completion callback.
  */
 static void
@@ -886,7 +886,7 @@ bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport,
        case RPSM_EVENT_LOGO_RCVD:
        case RPSM_EVENT_PRLO_RCVD:
        case RPSM_EVENT_ADDRESS_CHANGE:
-               /**
+               /*
                 * rport is already going offline.
                 * SCN - ignore and wait till transitioning to offline state
                 */
@@ -901,7 +901,7 @@ bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport,
        }
 }
 
-/**
+/*
  *             Rport is offline. FC-4s are offline. Awaiting BFA rport offline
  *             callback.
  */
@@ -945,7 +945,7 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport,
        case RPSM_EVENT_SCN:
        case RPSM_EVENT_LOGO_RCVD:
        case RPSM_EVENT_PRLO_RCVD:
-               /**
+               /*
                 * Ignore, already offline.
                 */
                break;
@@ -955,7 +955,7 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport,
        }
 }
 
-/**
+/*
  *             Rport is offline. FC-4s are offline. Awaiting BFA rport offline
  *             callback to send LOGO accept.
  */
@@ -1009,7 +1009,7 @@ bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport,
 
        case RPSM_EVENT_LOGO_RCVD:
        case RPSM_EVENT_PRLO_RCVD:
-               /**
+               /*
                 * Ignore - already processing a LOGO.
                 */
                break;
@@ -1019,7 +1019,7 @@ bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport,
        }
 }
 
-/**
+/*
  *             Rport is being deleted. FC-4s are offline.
  *  Awaiting BFA rport offline
  *             callback to send LOGO.
@@ -1048,7 +1048,7 @@ bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport,
        }
 }
 
-/**
+/*
  *             Rport is being deleted. FC-4s are offline. LOGO is being sent.
  */
 static void
@@ -1082,7 +1082,7 @@ bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport,
        }
 }
 
-/**
+/*
  *             Rport is offline. FC-4s are offline. BFA rport is offline.
  *             Timer active to delete stale rport.
  */
@@ -1142,7 +1142,7 @@ bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, enum rport_event event)
        }
 }
 
-/**
+/*
  *     Rport address has changed. Nameserver discovery request is being sent.
  */
 static void
@@ -1199,7 +1199,7 @@ bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport,
        }
 }
 
-/**
+/*
  *             Nameserver discovery failed. Waiting for timeout to retry.
  */
 static void
@@ -1263,7 +1263,7 @@ bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport,
        }
 }
 
-/**
+/*
  *             Rport address has changed. Nameserver discovery request is sent.
  */
 static void
@@ -1329,13 +1329,13 @@ bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport,
                bfa_fcs_rport_send_prlo_acc(rport);
                break;
        case RPSM_EVENT_SCN:
-               /**
+               /*
                 * ignore, wait for NS query response
                 */
                break;
 
        case RPSM_EVENT_LOGO_RCVD:
-               /**
+               /*
                 * Not logged-in yet. Accept LOGO.
                 */
                bfa_fcs_rport_send_logo_acc(rport);
@@ -1354,7 +1354,7 @@ bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport,
 
 
 
-/**
+/*
  *  fcs_rport_private FCS RPORT provate functions
  */
 
@@ -1415,7 +1415,7 @@ bfa_fcs_rport_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
 
        plogi_rsp = (struct fc_logi_s *) BFA_FCXP_RSP_PLD(fcxp);
 
-       /**
+       /*
         * Check for failure first.
         */
        if (plogi_rsp->els_cmd.els_code != FC_ELS_ACC) {
@@ -1436,7 +1436,7 @@ bfa_fcs_rport_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
                return;
        }
 
-       /**
+       /*
         * PLOGI is complete. Make sure this device is not one of the known
         * device with a new FC port address.
         */
@@ -1468,7 +1468,7 @@ bfa_fcs_rport_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
                }
        }
 
-       /**
+       /*
         * Normal login path -- no evil twins.
         */
        rport->stats.plogi_accs++;
@@ -1621,7 +1621,7 @@ bfa_fcs_rport_gidpn_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
        bfa_trc(rport->fcs, rport->pwwn);
 
        cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
-       cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+       cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
 
        if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
                /* Check if the pid is the same as before. */
@@ -1691,7 +1691,7 @@ bfa_fcs_rport_gpnid_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
        bfa_trc(rport->fcs, rport->pwwn);
 
        cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
-       cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+       cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);
 
        if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
                bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED);
@@ -1722,7 +1722,7 @@ bfa_fcs_rport_gpnid_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
        }
 }
 
-/**
+/*
  *     Called to send a logout to the rport.
  */
 static void
@@ -1759,7 +1759,7 @@ bfa_fcs_rport_send_logo(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
        bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
 }
 
-/**
+/*
  *     Send ACC for a LOGO received.
  */
 static void
@@ -1788,7 +1788,7 @@ bfa_fcs_rport_send_logo_acc(void *rport_cbarg)
                        FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0);
 }
 
-/**
+/*
  *     brief
  *     This routine will be called by bfa_timer on timer timeouts.
  *
@@ -1961,7 +1961,7 @@ bfa_fcs_rport_alloc(struct bfa_fcs_lport_s *port, wwn_t pwwn, u32 rpid)
        struct bfa_fcs_rport_s *rport;
        struct bfad_rport_s     *rport_drv;
 
-       /**
+       /*
         * allocate rport
         */
        if (bfa_fcb_rport_alloc(fcs->bfad, &rport, &rport_drv)
@@ -1979,7 +1979,7 @@ bfa_fcs_rport_alloc(struct bfa_fcs_lport_s *port, wwn_t pwwn, u32 rpid)
        rport->pid = rpid;
        rport->pwwn = pwwn;
 
-       /**
+       /*
         * allocate BFA rport
         */
        rport->bfa_rport = bfa_rport_create(port->fcs->bfa, rport);
@@ -1989,7 +1989,7 @@ bfa_fcs_rport_alloc(struct bfa_fcs_lport_s *port, wwn_t pwwn, u32 rpid)
                return NULL;
        }
 
-       /**
+       /*
         * allocate FC-4s
         */
        bfa_assert(bfa_fcs_lport_is_initiator(port));
@@ -2021,7 +2021,7 @@ bfa_fcs_rport_free(struct bfa_fcs_rport_s *rport)
 {
        struct bfa_fcs_lport_s *port = rport->port;
 
-       /**
+       /*
         * - delete FC-4s
         * - delete BFA rport
         * - remove from queue of rports
@@ -2093,7 +2093,7 @@ bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport)
        }
 }
 
-/**
+/*
  * Update rport parameters from PLOGI or PLOGI accept.
  */
 static void
@@ -2101,14 +2101,14 @@ bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, struct fc_logi_s *plogi)
 {
        bfa_fcs_lport_t *port = rport->port;
 
-       /**
+       /*
         * - port name
         * - node name
         */
        rport->pwwn = plogi->port_name;
        rport->nwwn = plogi->node_name;
 
-       /**
+       /*
         * - class of service
         */
        rport->fc_cos = 0;
@@ -2118,16 +2118,16 @@ bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, struct fc_logi_s *plogi)
        if (plogi->class2.class_valid)
                rport->fc_cos |= FC_CLASS_2;
 
-       /**
+       /*
         * - CISC
         * - MAX receive frame size
         */
        rport->cisc = plogi->csp.cisc;
-       rport->maxfrsize = bfa_os_ntohs(plogi->class3.rxsz);
+       rport->maxfrsize = be16_to_cpu(plogi->class3.rxsz);
 
-       bfa_trc(port->fcs, bfa_os_ntohs(plogi->csp.bbcred));
+       bfa_trc(port->fcs, be16_to_cpu(plogi->csp.bbcred));
        bfa_trc(port->fcs, port->fabric->bb_credit);
-       /**
+       /*
         * Direct Attach P2P mode :
         * This is to handle a bug (233476) in IBM targets in Direct Attach
         *  Mode. Basically, in FLOGI Accept the target would have
@@ -2136,19 +2136,19 @@ bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, struct fc_logi_s *plogi)
         * in PLOGI.
         */
        if ((!bfa_fcs_fabric_is_switched(port->fabric))  &&
-               (bfa_os_ntohs(plogi->csp.bbcred) < port->fabric->bb_credit)) {
+               (be16_to_cpu(plogi->csp.bbcred) < port->fabric->bb_credit)) {
 
-               bfa_trc(port->fcs, bfa_os_ntohs(plogi->csp.bbcred));
+               bfa_trc(port->fcs, be16_to_cpu(plogi->csp.bbcred));
                bfa_trc(port->fcs, port->fabric->bb_credit);
 
-               port->fabric->bb_credit = bfa_os_ntohs(plogi->csp.bbcred);
+               port->fabric->bb_credit = be16_to_cpu(plogi->csp.bbcred);
                bfa_fcport_set_tx_bbcredit(port->fcs->bfa,
                                          port->fabric->bb_credit);
        }
 
 }
 
-/**
+/*
  *     Called to handle LOGO received from an existing remote port.
  */
 static void
@@ -2164,11 +2164,11 @@ bfa_fcs_rport_process_logo(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs)
 
 
 
-/**
+/*
  *  fcs_rport_public FCS rport public interfaces
  */
 
-/**
+/*
  *     Called by bport/vport to create a remote port instance for a discovered
  *     remote device.
  *
@@ -2191,7 +2191,7 @@ bfa_fcs_rport_create(struct bfa_fcs_lport_s *port, u32 rpid)
        return rport;
 }
 
-/**
+/*
  * Called to create a rport for which only the wwn is known.
  *
  * @param[in] port     - base port
@@ -2211,7 +2211,7 @@ bfa_fcs_rport_create_by_wwn(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
        bfa_sm_send_event(rport, RPSM_EVENT_ADDRESS_DISC);
        return rport;
 }
-/**
+/*
  * Called by bport in private loop topology to indicate that a
  * rport has been discovered and plogi has been completed.
  *
@@ -2233,7 +2233,7 @@ bfa_fcs_rport_start(struct bfa_fcs_lport_s *port, struct fchs_s *fchs,
        bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_COMP);
 }
 
-/**
+/*
  *     Called by bport/vport to handle PLOGI received from a new remote port.
  *     If an existing rport does a plogi, it will be handled separately.
  */
@@ -2272,7 +2272,7 @@ wwn_compare(wwn_t wwn1, wwn_t wwn2)
        return 0;
 }
 
-/**
+/*
  *     Called by bport/vport to handle PLOGI received from an existing
  *      remote port.
  */
@@ -2280,7 +2280,7 @@ void
 bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs,
                        struct fc_logi_s *plogi)
 {
-       /**
+       /*
         * @todo Handle P2P and initiator-initiator.
         */
 
@@ -2289,7 +2289,7 @@ bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs,
        rport->reply_oxid = rx_fchs->ox_id;
        bfa_trc(rport->fcs, rport->reply_oxid);
 
-       /**
+       /*
         * In Switched fabric topology,
         * PLOGI to each other. If our pwwn is smaller, ignore it,
         * if it is not a well known address.
@@ -2307,7 +2307,7 @@ bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs,
        bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RCVD);
 }
 
-/**
+/*
  * Called by bport/vport to delete a remote port instance.
  *
  * Rport delete is called under the following conditions:
@@ -2321,7 +2321,7 @@ bfa_fcs_rport_delete(struct bfa_fcs_rport_s *rport)
        bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
 }
 
-/**
+/*
  * Called by bport/vport to  when a target goes offline.
  *
  */
@@ -2331,7 +2331,7 @@ bfa_fcs_rport_offline(struct bfa_fcs_rport_s *rport)
        bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);
 }
 
-/**
+/*
  * Called by bport in n2n when a target (attached port) becomes online.
  *
  */
@@ -2340,7 +2340,7 @@ bfa_fcs_rport_online(struct bfa_fcs_rport_s *rport)
 {
        bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_SEND);
 }
-/**
+/*
  *     Called by bport/vport to notify SCN for the remote port
  */
 void
@@ -2350,7 +2350,7 @@ bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport)
        bfa_sm_send_event(rport, RPSM_EVENT_SCN);
 }
 
-/**
+/*
  *     Called by       fcpim to notify that the ITN cleanup is done.
  */
 void
@@ -2359,7 +2359,7 @@ bfa_fcs_rport_itnim_ack(struct bfa_fcs_rport_s *rport)
        bfa_sm_send_event(rport, RPSM_EVENT_FC4_OFFLINE);
 }
 
-/**
+/*
  *     Called by fcptm to notify that the ITN cleanup is done.
  */
 void
@@ -2368,7 +2368,7 @@ bfa_fcs_rport_tin_ack(struct bfa_fcs_rport_s *rport)
        bfa_sm_send_event(rport, RPSM_EVENT_FC4_OFFLINE);
 }
 
-/**
+/*
  *     brief
  *     This routine BFA callback for bfa_rport_online() call.
  *
@@ -2391,7 +2391,7 @@ bfa_cb_rport_online(void *cbarg)
        bfa_sm_send_event(rport, RPSM_EVENT_HCB_ONLINE);
 }
 
-/**
+/*
  *     brief
  *     This routine BFA callback for bfa_rport_offline() call.
  *
@@ -2413,7 +2413,7 @@ bfa_cb_rport_offline(void *cbarg)
        bfa_sm_send_event(rport, RPSM_EVENT_HCB_OFFLINE);
 }
 
-/**
+/*
  *     brief
  *     This routine is a static BFA callback when there is a QoS flow_id
  *     change notification
@@ -2437,7 +2437,7 @@ bfa_cb_rport_qos_scn_flowid(void *cbarg,
        bfa_trc(rport->fcs, rport->pwwn);
 }
 
-/**
+/*
  *     brief
  *     This routine is a static BFA callback when there is a QoS priority
  *     change notification
@@ -2461,7 +2461,7 @@ bfa_cb_rport_qos_scn_prio(void *cbarg,
        bfa_trc(rport->fcs, rport->pwwn);
 }
 
-/**
+/*
  *             Called to process any unsolicted frames from this remote port
  */
 void
@@ -2470,7 +2470,7 @@ bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport)
        bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);
 }
 
-/**
+/*
  *             Called to process any unsolicted frames from this remote port
  */
 void
@@ -2577,7 +2577,7 @@ bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs,
                        FC_MAX_PDUSZ, 0);
 }
 
-/**
+/*
  * Return state of rport.
  */
 int
@@ -2586,7 +2586,7 @@ bfa_fcs_rport_get_state(struct bfa_fcs_rport_s *rport)
        return bfa_sm_to_state(rport_sm_table, rport->sm);
 }
 
-/**
+/*
  *     brief
  *              Called by the Driver to set rport delete/ageout timeout
  *
@@ -2613,15 +2613,15 @@ bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, u16 ox_id)
 
 
 
-/**
+/*
  * Remote port implementation.
  */
 
-/**
+/*
  *  fcs_rport_api FCS rport API.
  */
 
-/**
+/*
  *     Direct API to add a target by port wwn. This interface is used, for
  *     example, by bios when target pwwn is known from boot lun configuration.
  */
@@ -2634,7 +2634,7 @@ bfa_fcs_rport_add(struct bfa_fcs_lport_s *port, wwn_t *pwwn,
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  *     Direct API to remove a target and its associated resources. This
  *     interface is used, for example, by driver to remove target
  *     ports from the target list for a VM.
@@ -2663,7 +2663,7 @@ bfa_fcs_rport_remove(struct bfa_fcs_rport_s *rport_in)
 
 }
 
-/**
+/*
  *     Remote device status for display/debug.
  */
 void
@@ -2674,7 +2674,7 @@ bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport,
        bfa_fcs_lport_t *port = rport->port;
        bfa_port_speed_t rport_speed = rport->rpf.rpsc_speed;
 
-       bfa_os_memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s));
+       memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s));
 
        rport_attr->pid = rport->pid;
        rport_attr->pwwn = rport->pwwn;
@@ -2704,7 +2704,7 @@ bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport,
        }
 }
 
-/**
+/*
  *     Per remote device statistics.
  */
 void
@@ -2717,7 +2717,7 @@ bfa_fcs_rport_get_stats(struct bfa_fcs_rport_s *rport,
 void
 bfa_fcs_rport_clear_stats(struct bfa_fcs_rport_s *rport)
 {
-       bfa_os_memset((char *)&rport->stats, 0,
+       memset((char *)&rport->stats, 0,
                        sizeof(struct bfa_rport_stats_s));
 }
 
@@ -2767,7 +2767,7 @@ bfa_fcs_rport_set_speed(struct bfa_fcs_rport_s *rport, bfa_port_speed_t speed)
 
 
 
-/**
+/*
  * Remote port features (RPF) implementation.
  */
 
@@ -2786,7 +2786,7 @@ static void     bfa_fcs_rpf_rpsc2_response(void *fcsarg,
 
 static void     bfa_fcs_rpf_timeout(void *arg);
 
-/**
+/*
  *  fcs_rport_ftrs_sm FCS rport state machine events
  */
 
@@ -2981,7 +2981,7 @@ bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
                bfa_sm_fault(rport->fcs, event);
        }
 }
-/**
+/*
  * Called when Rport is created.
  */
 void
@@ -2995,7 +2995,7 @@ bfa_fcs_rpf_init(struct bfa_fcs_rport_s *rport)
        bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_uninit);
 }
 
-/**
+/*
  * Called when Rport becomes online
  */
 void
@@ -3010,7 +3010,7 @@ bfa_fcs_rpf_rport_online(struct bfa_fcs_rport_s *rport)
                bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_ONLINE);
 }
 
-/**
+/*
  * Called when Rport becomes offline
  */
 void
@@ -3090,16 +3090,16 @@ bfa_fcs_rpf_rpsc2_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
        rpsc2_acc = (struct fc_rpsc2_acc_s *) BFA_FCXP_RSP_PLD(fcxp);
        if (rpsc2_acc->els_cmd == FC_ELS_ACC) {
                rport->stats.rpsc_accs++;
-               num_ents = bfa_os_ntohs(rpsc2_acc->num_pids);
+               num_ents = be16_to_cpu(rpsc2_acc->num_pids);
                bfa_trc(rport->fcs, num_ents);
                if (num_ents > 0) {
                        bfa_assert(rpsc2_acc->port_info[0].pid != rport->pid);
                        bfa_trc(rport->fcs,
-                               bfa_os_ntohs(rpsc2_acc->port_info[0].pid));
+                               be16_to_cpu(rpsc2_acc->port_info[0].pid));
                        bfa_trc(rport->fcs,
-                               bfa_os_ntohs(rpsc2_acc->port_info[0].speed));
+                               be16_to_cpu(rpsc2_acc->port_info[0].speed));
                        bfa_trc(rport->fcs,
-                               bfa_os_ntohs(rpsc2_acc->port_info[0].index));
+                               be16_to_cpu(rpsc2_acc->port_info[0].index));
                        bfa_trc(rport->fcs,
                                rpsc2_acc->port_info[0].type);
 
@@ -3109,7 +3109,7 @@ bfa_fcs_rpf_rpsc2_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
                        }
 
                        rpf->rpsc_speed = fc_rpsc_operspeed_to_bfa_speed(
-                               bfa_os_ntohs(rpsc2_acc->port_info[0].speed));
+                               be16_to_cpu(rpsc2_acc->port_info[0].speed));
 
                        bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_COMP);
                }
index c787d3af0886e2172d6180d792c5202c695b9a30..d8464ae60070438b01ed785d2bd667042eb1160d 100644 (file)
@@ -22,7 +22,7 @@ void
 bfa_hwcb_reginit(struct bfa_s *bfa)
 {
        struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs;
-       bfa_os_addr_t           kva = bfa_ioc_bar0(&bfa->ioc);
+       void __iomem *kva = bfa_ioc_bar0(&bfa->ioc);
        int                     i, q, fn = bfa_ioc_pcifn(&bfa->ioc);
 
        if (fn == 0) {
@@ -60,8 +60,8 @@ bfa_hwcb_reqq_ack(struct bfa_s *bfa, int reqq)
 static void
 bfa_hwcb_reqq_ack_msix(struct bfa_s *bfa, int reqq)
 {
-       bfa_reg_write(bfa->iocfc.bfa_regs.intr_status,
-               __HFN_INT_CPE_Q0 << CPE_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), reqq));
+       writel(__HFN_INT_CPE_Q0 << CPE_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), reqq),
+                       bfa->iocfc.bfa_regs.intr_status);
 }
 
 void
@@ -72,8 +72,8 @@ bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq)
 static void
 bfa_hwcb_rspq_ack_msix(struct bfa_s *bfa, int rspq)
 {
-       bfa_reg_write(bfa->iocfc.bfa_regs.intr_status,
-               __HFN_INT_RME_Q0 << RME_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), rspq));
+       writel(__HFN_INT_RME_Q0 << RME_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), rspq),
+                       bfa->iocfc.bfa_regs.intr_status);
 }
 
 void
@@ -102,7 +102,7 @@ bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap,
        *num_vecs = __HFN_NUMINTS;
 }
 
-/**
+/*
  * No special setup required for crossbow -- vector assignments are implicit.
  */
 void
@@ -129,7 +129,7 @@ bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs)
                bfa->msix.handler[i] = bfa_msix_lpu_err;
 }
 
-/**
+/*
  * Crossbow -- dummy, interrupts are masked
  */
 void
@@ -142,7 +142,7 @@ bfa_hwcb_msix_uninstall(struct bfa_s *bfa)
 {
 }
 
-/**
+/*
  * No special enable/disable -- vector assignments are implicit.
  */
 void
index c97ebafec5ea980ec0a4597aa9ac4719001184fd..b0efbc713ffe7c12a83bffe2172876d11baff9da 100644 (file)
@@ -31,15 +31,15 @@ static void
 bfa_hwct_msix_lpu_err_set(struct bfa_s *bfa, bfa_boolean_t msix, int vec)
 {
        int fn = bfa_ioc_pcifn(&bfa->ioc);
-       bfa_os_addr_t kva = bfa_ioc_bar0(&bfa->ioc);
+       void __iomem *kva = bfa_ioc_bar0(&bfa->ioc);
 
        if (msix)
-               bfa_reg_write(kva + __ct_msix_err_vec_reg[fn], vec);
+               writel(vec, kva + __ct_msix_err_vec_reg[fn]);
        else
-               bfa_reg_write(kva + __ct_msix_err_vec_reg[fn], 0);
+               writel(0, kva + __ct_msix_err_vec_reg[fn]);
 }
 
-/**
+/*
  * Dummy interrupt handler for handling spurious interrupt during chip-reinit.
  */
 static void
@@ -51,7 +51,7 @@ void
 bfa_hwct_reginit(struct bfa_s *bfa)
 {
        struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs;
-       bfa_os_addr_t           kva = bfa_ioc_bar0(&bfa->ioc);
+       void __iomem *kva = bfa_ioc_bar0(&bfa->ioc);
        int                     i, q, fn = bfa_ioc_pcifn(&bfa->ioc);
 
        if (fn == 0) {
@@ -88,8 +88,8 @@ bfa_hwct_reqq_ack(struct bfa_s *bfa, int reqq)
 {
        u32     r32;
 
-       r32 = bfa_reg_read(bfa->iocfc.bfa_regs.cpe_q_ctrl[reqq]);
-       bfa_reg_write(bfa->iocfc.bfa_regs.cpe_q_ctrl[reqq], r32);
+       r32 = readl(bfa->iocfc.bfa_regs.cpe_q_ctrl[reqq]);
+       writel(r32, bfa->iocfc.bfa_regs.cpe_q_ctrl[reqq]);
 }
 
 void
@@ -97,8 +97,8 @@ bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq)
 {
        u32     r32;
 
-       r32 = bfa_reg_read(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq]);
-       bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq], r32);
+       r32 = readl(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq]);
+       writel(r32, bfa->iocfc.bfa_regs.rme_q_ctrl[rspq]);
 }
 
 void
@@ -110,7 +110,7 @@ bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap,
        *num_vecs = BFA_MSIX_CT_MAX;
 }
 
-/**
+/*
  * Setup MSI-X vector for catapult
  */
 void
@@ -156,7 +156,7 @@ bfa_hwct_msix_uninstall(struct bfa_s *bfa)
                bfa->msix.handler[i] = bfa_hwct_msix_dummy;
 }
 
-/**
+/*
  * Enable MSI-X vectors
  */
 void
index 6795b247791a5d48f8b4572997f5f68afbd7ec95..54475b53a5ab1494490f2561fdc0c9d7884c0a55 100644 (file)
@@ -23,7 +23,7 @@
 
 BFA_TRC_FILE(CNA, IOC);
 
-/**
+/*
  * IOC local definitions
  */
 #define BFA_IOC_TOV            3000    /* msecs */
@@ -49,7 +49,7 @@ BFA_TRC_FILE(CNA, IOC);
          BFA_TRC_MAX * sizeof(struct bfa_trc_s)))
 #define BFA_DBG_FWTRC_OFF(_fn) (BFI_IOC_TRC_OFF + BFA_DBG_FWTRC_LEN * (_fn))
 
-/**
+/*
  * Asic specific macros : see bfa_hw_cb.c and bfa_hw_ct.c for details.
  */
 
@@ -73,7 +73,7 @@ BFA_TRC_FILE(CNA, IOC);
 
 #define bfa_ioc_mbox_cmd_pending(__ioc)                \
                        (!list_empty(&((__ioc)->mbox_mod.cmd_q)) || \
-                       bfa_reg_read((__ioc)->ioc_regs.hfn_mbox_cmd))
+                       readl((__ioc)->ioc_regs.hfn_mbox_cmd))
 
 bfa_boolean_t bfa_auto_recover = BFA_TRUE;
 
@@ -101,11 +101,11 @@ static void bfa_ioc_pf_disabled(struct bfa_ioc_s *ioc);
 static void bfa_ioc_pf_failed(struct bfa_ioc_s *ioc);
 static void bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc);
 
-/**
+/*
  *  hal_ioc_sm
  */
 
-/**
+/*
  * IOC state machine definitions/declarations
  */
 enum ioc_event {
@@ -144,7 +144,7 @@ static struct bfa_sm_table_s ioc_sm_table[] = {
        {BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED},
 };
 
-/**
+/*
  * IOCPF state machine definitions/declarations
  */
 
@@ -174,7 +174,7 @@ static void bfa_iocpf_stop(struct bfa_ioc_s *ioc);
 static void bfa_iocpf_timeout(void *ioc_arg);
 static void bfa_iocpf_sem_timeout(void *ioc_arg);
 
-/**
+/*
  * IOCPF state machine events
  */
 enum iocpf_event {
@@ -191,7 +191,7 @@ enum iocpf_event {
        IOCPF_E_TIMEOUT         = 11,   /*  f/w response timeout        */
 };
 
-/**
+/*
  * IOCPF states
  */
 enum bfa_iocpf_state {
@@ -232,11 +232,11 @@ static struct bfa_sm_table_s iocpf_sm_table[] = {
        {BFA_SM(bfa_iocpf_sm_disabled), BFA_IOCPF_DISABLED},
 };
 
-/**
+/*
  * IOC State Machine
  */
 
-/**
+/*
  * Beginning state. IOC uninit state.
  */
 
@@ -245,7 +245,7 @@ bfa_ioc_sm_uninit_entry(struct bfa_ioc_s *ioc)
 {
 }
 
-/**
+/*
  * IOC is in uninit state.
  */
 static void
@@ -262,7 +262,7 @@ bfa_ioc_sm_uninit(struct bfa_ioc_s *ioc, enum ioc_event event)
                bfa_sm_fault(ioc, event);
        }
 }
-/**
+/*
  * Reset entry actions -- initialize state machine
  */
 static void
@@ -271,7 +271,7 @@ bfa_ioc_sm_reset_entry(struct bfa_ioc_s *ioc)
        bfa_fsm_set_state(&ioc->iocpf, bfa_iocpf_sm_reset);
 }
 
-/**
+/*
  * IOC is in reset state.
  */
 static void
@@ -304,7 +304,7 @@ bfa_ioc_sm_enabling_entry(struct bfa_ioc_s *ioc)
        bfa_iocpf_enable(ioc);
 }
 
-/**
+/*
  * Host IOC function is being enabled, awaiting response from firmware.
  * Semaphore is acquired.
  */
@@ -352,7 +352,7 @@ bfa_ioc_sm_getattr_entry(struct bfa_ioc_s *ioc)
        bfa_ioc_send_getattr(ioc);
 }
 
-/**
+/*
  * IOC configuration in progress. Timer is active.
  */
 static void
@@ -447,7 +447,7 @@ bfa_ioc_sm_disabling_entry(struct bfa_ioc_s *ioc)
        BFA_LOG(KERN_INFO, bfad, log_level, "IOC disabled\n");
 }
 
-/**
+/*
  * IOC is being disabled
  */
 static void
@@ -474,7 +474,7 @@ bfa_ioc_sm_disabling(struct bfa_ioc_s *ioc, enum ioc_event event)
        }
 }
 
-/**
+/*
  * IOC disable completion entry.
  */
 static void
@@ -514,7 +514,7 @@ bfa_ioc_sm_initfail_entry(struct bfa_ioc_s *ioc)
        ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
 }
 
-/**
+/*
  * Hardware initialization failed.
  */
 static void
@@ -528,7 +528,7 @@ bfa_ioc_sm_initfail(struct bfa_ioc_s *ioc, enum ioc_event event)
                break;
 
        case IOC_E_FAILED:
-               /**
+               /*
                 * Initialization failure during iocpf init retry.
                 */
                ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
@@ -556,7 +556,7 @@ bfa_ioc_sm_fail_entry(struct bfa_ioc_s *ioc)
        struct bfa_ioc_hbfail_notify_s  *notify;
        struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;
 
-       /**
+       /*
         * Notify driver and common modules registered for notification.
         */
        ioc->cbfn->hbfail_cbfn(ioc->bfa);
@@ -569,7 +569,7 @@ bfa_ioc_sm_fail_entry(struct bfa_ioc_s *ioc)
                "Heart Beat of IOC has failed\n");
 }
 
-/**
+/*
  * IOC failure.
  */
 static void
@@ -580,7 +580,7 @@ bfa_ioc_sm_fail(struct bfa_ioc_s *ioc, enum ioc_event event)
        switch (event) {
 
        case IOC_E_FAILED:
-               /**
+               /*
                 * Initialization failure during iocpf recovery.
                 * !!! Fall through !!!
                 */
@@ -608,12 +608,12 @@ bfa_ioc_sm_fail(struct bfa_ioc_s *ioc, enum ioc_event event)
 
 
 
-/**
+/*
  * IOCPF State Machine
  */
 
 
-/**
+/*
  * Reset entry actions -- initialize state machine
  */
 static void
@@ -623,7 +623,7 @@ bfa_iocpf_sm_reset_entry(struct bfa_iocpf_s *iocpf)
        iocpf->auto_recover = bfa_auto_recover;
 }
 
-/**
+/*
  * Beginning state. IOC is in reset state.
  */
 static void
@@ -646,7 +646,7 @@ bfa_iocpf_sm_reset(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
        }
 }
 
-/**
+/*
  * Semaphore should be acquired for version check.
  */
 static void
@@ -655,7 +655,7 @@ bfa_iocpf_sm_fwcheck_entry(struct bfa_iocpf_s *iocpf)
        bfa_ioc_hw_sem_get(iocpf->ioc);
 }
 
-/**
+/*
  * Awaiting h/w semaphore to continue with version check.
  */
 static void
@@ -692,7 +692,7 @@ bfa_iocpf_sm_fwcheck(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
        }
 }
 
-/**
+/*
  * Notify enable completion callback.
  */
 static void
@@ -708,7 +708,7 @@ bfa_iocpf_sm_mismatch_entry(struct bfa_iocpf_s *iocpf)
        bfa_iocpf_timer_start(iocpf->ioc);
 }
 
-/**
+/*
  * Awaiting firmware version match.
  */
 static void
@@ -739,7 +739,7 @@ bfa_iocpf_sm_mismatch(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
        }
 }
 
-/**
+/*
  * Request for semaphore.
  */
 static void
@@ -748,7 +748,7 @@ bfa_iocpf_sm_semwait_entry(struct bfa_iocpf_s *iocpf)
        bfa_ioc_hw_sem_get(iocpf->ioc);
 }
 
-/**
+/*
  * Awaiting semaphore for h/w initialzation.
  */
 static void
@@ -782,7 +782,7 @@ bfa_iocpf_sm_hwinit_entry(struct bfa_iocpf_s *iocpf)
        bfa_ioc_reset(iocpf->ioc, BFA_FALSE);
 }
 
-/**
+/*
  * Hardware is being initialized. Interrupts are enabled.
  * Holding hardware semaphore lock.
  */
@@ -839,7 +839,7 @@ bfa_iocpf_sm_enabling_entry(struct bfa_iocpf_s *iocpf)
        bfa_ioc_send_enable(iocpf->ioc);
 }
 
-/**
+/*
  * Host IOC function is being enabled, awaiting response from firmware.
  * Semaphore is acquired.
  */
@@ -866,8 +866,7 @@ bfa_iocpf_sm_enabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
        case IOCPF_E_TIMEOUT:
                iocpf->retry_count++;
                if (iocpf->retry_count < BFA_IOC_HWINIT_MAX) {
-                       bfa_reg_write(ioc->ioc_regs.ioc_fwstate,
-                                     BFI_IOC_UNINIT);
+                       writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate);
                        bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
                        break;
                }
@@ -944,7 +943,7 @@ bfa_iocpf_sm_disabling_entry(struct bfa_iocpf_s *iocpf)
        bfa_ioc_send_disable(iocpf->ioc);
 }
 
-/**
+/*
  * IOC is being disabled
  */
 static void
@@ -968,7 +967,7 @@ bfa_iocpf_sm_disabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
                 */
 
        case IOCPF_E_TIMEOUT:
-               bfa_reg_write(ioc->ioc_regs.ioc_fwstate, BFI_IOC_FAIL);
+               writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
                bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
                break;
 
@@ -980,7 +979,7 @@ bfa_iocpf_sm_disabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
        }
 }
 
-/**
+/*
  * IOC disable completion entry.
  */
 static void
@@ -1018,7 +1017,7 @@ bfa_iocpf_sm_initfail_entry(struct bfa_iocpf_s *iocpf)
        bfa_iocpf_timer_start(iocpf->ioc);
 }
 
-/**
+/*
  * Hardware initialization failed.
  */
 static void
@@ -1053,18 +1052,18 @@ bfa_iocpf_sm_initfail(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
 static void
 bfa_iocpf_sm_fail_entry(struct bfa_iocpf_s *iocpf)
 {
-       /**
+       /*
         * Mark IOC as failed in hardware and stop firmware.
         */
        bfa_ioc_lpu_stop(iocpf->ioc);
-       bfa_reg_write(iocpf->ioc->ioc_regs.ioc_fwstate, BFI_IOC_FAIL);
+       writel(BFI_IOC_FAIL, iocpf->ioc->ioc_regs.ioc_fwstate);
 
-       /**
+       /*
         * Notify other functions on HB failure.
         */
        bfa_ioc_notify_hbfail(iocpf->ioc);
 
-       /**
+       /*
         * Flush any queued up mailbox requests.
         */
        bfa_ioc_mbox_hbfail(iocpf->ioc);
@@ -1073,7 +1072,7 @@ bfa_iocpf_sm_fail_entry(struct bfa_iocpf_s *iocpf)
                bfa_iocpf_recovery_timer_start(iocpf->ioc);
 }
 
-/**
+/*
  * IOC is in failed state.
  */
 static void
@@ -1101,7 +1100,7 @@ bfa_iocpf_sm_fail(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
 
 
 
-/**
+/*
  *  hal_ioc_pvt BFA IOC private functions
  */
 
@@ -1113,7 +1112,7 @@ bfa_ioc_disable_comp(struct bfa_ioc_s *ioc)
 
        ioc->cbfn->disable_cbfn(ioc->bfa);
 
-       /**
+       /*
         * Notify common modules registered for notification.
         */
        list_for_each(qe, &ioc->hb_notify_q) {
@@ -1123,18 +1122,18 @@ bfa_ioc_disable_comp(struct bfa_ioc_s *ioc)
 }
 
 bfa_boolean_t
-bfa_ioc_sem_get(bfa_os_addr_t sem_reg)
+bfa_ioc_sem_get(void __iomem *sem_reg)
 {
        u32 r32;
        int cnt = 0;
 #define BFA_SEM_SPINCNT        3000
 
-       r32 = bfa_reg_read(sem_reg);
+       r32 = readl(sem_reg);
 
        while (r32 && (cnt < BFA_SEM_SPINCNT)) {
                cnt++;
-               bfa_os_udelay(2);
-               r32 = bfa_reg_read(sem_reg);
+               udelay(2);
+               r32 = readl(sem_reg);
        }
 
        if (r32 == 0)
@@ -1145,9 +1144,9 @@ bfa_ioc_sem_get(bfa_os_addr_t sem_reg)
 }
 
 void
-bfa_ioc_sem_release(bfa_os_addr_t sem_reg)
+bfa_ioc_sem_release(void __iomem *sem_reg)
 {
-       bfa_reg_write(sem_reg, 1);
+       writel(1, sem_reg);
 }
 
 static void
@@ -1155,11 +1154,11 @@ bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc)
 {
        u32     r32;
 
-       /**
+       /*
         * First read to the semaphore register will return 0, subsequent reads
         * will return 1. Semaphore is released by writing 1 to the register
         */
-       r32 = bfa_reg_read(ioc->ioc_regs.ioc_sem_reg);
+       r32 = readl(ioc->ioc_regs.ioc_sem_reg);
        if (r32 == 0) {
                bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEMLOCKED);
                return;
@@ -1171,7 +1170,7 @@ bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc)
 void
 bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc)
 {
-       bfa_reg_write(ioc->ioc_regs.ioc_sem_reg, 1);
+       writel(1, ioc->ioc_regs.ioc_sem_reg);
 }
 
 static void
@@ -1180,7 +1179,7 @@ bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc)
        bfa_sem_timer_stop(ioc);
 }
 
-/**
+/*
  * Initialize LPU local memory (aka secondary memory / SRAM)
  */
 static void
@@ -1190,7 +1189,7 @@ bfa_ioc_lmem_init(struct bfa_ioc_s *ioc)
        int             i;
 #define PSS_LMEM_INIT_TIME  10000
 
-       pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
+       pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
        pss_ctl &= ~__PSS_LMEM_RESET;
        pss_ctl |= __PSS_LMEM_INIT_EN;
 
@@ -1198,18 +1197,18 @@ bfa_ioc_lmem_init(struct bfa_ioc_s *ioc)
         * i2c workaround 12.5khz clock
         */
        pss_ctl |= __PSS_I2C_CLK_DIV(3UL);
-       bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
+       writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
 
-       /**
+       /*
         * wait for memory initialization to be complete
         */
        i = 0;
        do {
-               pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
+               pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
                i++;
        } while (!(pss_ctl & __PSS_LMEM_INIT_DONE) && (i < PSS_LMEM_INIT_TIME));
 
-       /**
+       /*
         * If memory initialization is not successful, IOC timeout will catch
         * such failures.
         */
@@ -1217,7 +1216,7 @@ bfa_ioc_lmem_init(struct bfa_ioc_s *ioc)
        bfa_trc(ioc, pss_ctl);
 
        pss_ctl &= ~(__PSS_LMEM_INIT_DONE | __PSS_LMEM_INIT_EN);
-       bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
+       writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
 }
 
 static void
@@ -1225,13 +1224,13 @@ bfa_ioc_lpu_start(struct bfa_ioc_s *ioc)
 {
        u32     pss_ctl;
 
-       /**
+       /*
         * Take processor out of reset.
         */
-       pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
+       pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
        pss_ctl &= ~__PSS_LPU0_RESET;
 
-       bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
+       writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
 }
 
 static void
@@ -1239,16 +1238,16 @@ bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc)
 {
        u32     pss_ctl;
 
-       /**
+       /*
         * Put processors in reset.
         */
-       pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
+       pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
        pss_ctl |= (__PSS_LPU0_RESET | __PSS_LPU1_RESET);
 
-       bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
+       writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
 }
 
-/**
+/*
  * Get driver and firmware versions.
  */
 void
@@ -1261,7 +1260,7 @@ bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr)
 
        pgnum = bfa_ioc_smem_pgnum(ioc, loff);
        pgoff = bfa_ioc_smem_pgoff(ioc, loff);
-       bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+       writel(pgnum, ioc->ioc_regs.host_page_num_fn);
 
        for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr_s) / sizeof(u32));
             i++) {
@@ -1271,7 +1270,7 @@ bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr)
        }
 }
 
-/**
+/*
  * Returns TRUE if same.
  */
 bfa_boolean_t
@@ -1296,7 +1295,7 @@ bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr)
        return BFA_TRUE;
 }
 
-/**
+/*
  * Return true if current running version is valid. Firmware signature and
  * execution context (driver/bios) must match.
  */
@@ -1305,7 +1304,7 @@ bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc, u32 boot_env)
 {
        struct bfi_ioc_image_hdr_s fwhdr, *drv_fwhdr;
 
-       /**
+       /*
         * If bios/efi boot (flash based) -- return true
         */
        if (bfa_ioc_is_bios_optrom(ioc))
@@ -1321,7 +1320,7 @@ bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc, u32 boot_env)
                return BFA_FALSE;
        }
 
-       if (bfa_os_swap32(fwhdr.param) != boot_env) {
+       if (swab32(fwhdr.param) != boot_env) {
                bfa_trc(ioc, fwhdr.param);
                bfa_trc(ioc, boot_env);
                return BFA_FALSE;
@@ -1330,7 +1329,7 @@ bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc, u32 boot_env)
        return bfa_ioc_fwver_cmp(ioc, &fwhdr);
 }
 
-/**
+/*
  * Conditionally flush any pending message from firmware at start.
  */
 static void
@@ -1338,9 +1337,9 @@ bfa_ioc_msgflush(struct bfa_ioc_s *ioc)
 {
        u32     r32;
 
-       r32 = bfa_reg_read(ioc->ioc_regs.lpu_mbox_cmd);
+       r32 = readl(ioc->ioc_regs.lpu_mbox_cmd);
        if (r32)
-               bfa_reg_write(ioc->ioc_regs.lpu_mbox_cmd, 1);
+               writel(1, ioc->ioc_regs.lpu_mbox_cmd);
 }
 
 
@@ -1352,7 +1351,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
        u32 boot_type;
        u32 boot_env;
 
-       ioc_fwstate = bfa_reg_read(ioc->ioc_regs.ioc_fwstate);
+       ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate);
 
        if (force)
                ioc_fwstate = BFI_IOC_UNINIT;
@@ -1362,7 +1361,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
        boot_type = BFI_BOOT_TYPE_NORMAL;
        boot_env = BFI_BOOT_LOADER_OS;
 
-       /**
+       /*
         * Flash based firmware boot BIOS env.
         */
        if (bfa_ioc_is_bios_optrom(ioc)) {
@@ -1370,7 +1369,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
                boot_env = BFI_BOOT_LOADER_BIOS;
        }
 
-       /**
+       /*
         * Flash based firmware boot UEFI env.
         */
        if (bfa_ioc_is_uefi(ioc)) {
@@ -1378,7 +1377,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
                boot_env = BFI_BOOT_LOADER_UEFI;
        }
 
-       /**
+       /*
         * check if firmware is valid
         */
        fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ?
@@ -1389,7 +1388,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
                return;
        }
 
-       /**
+       /*
         * If hardware initialization is in progress (initialized by other IOC),
         * just wait for an initialization completion interrupt.
         */
@@ -1398,7 +1397,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
                return;
        }
 
-       /**
+       /*
         * If IOC function is disabled and firmware version is same,
         * just re-enable IOC.
         *
@@ -1409,7 +1408,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
        if (ioc_fwstate == BFI_IOC_DISABLED ||
            (!bfa_ioc_is_bios_optrom(ioc) && ioc_fwstate == BFI_IOC_OP)) {
 
-               /**
+               /*
                 * When using MSI-X any pending firmware ready event should
                 * be flushed. Otherwise MSI-X interrupts are not delivered.
                 */
@@ -1419,7 +1418,7 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
                return;
        }
 
-       /**
+       /*
         * Initialize the h/w for any other states.
         */
        bfa_ioc_boot(ioc, boot_type, boot_env);
@@ -1449,17 +1448,17 @@ bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len)
         * first write msg to mailbox registers
         */
        for (i = 0; i < len / sizeof(u32); i++)
-               bfa_reg_write(ioc->ioc_regs.hfn_mbox + i * sizeof(u32),
-                             bfa_os_wtole(msgp[i]));
+               writel(cpu_to_le32(msgp[i]),
+                       ioc->ioc_regs.hfn_mbox + i * sizeof(u32));
 
        for (; i < BFI_IOC_MSGLEN_MAX / sizeof(u32); i++)
-               bfa_reg_write(ioc->ioc_regs.hfn_mbox + i * sizeof(u32), 0);
+               writel(0, ioc->ioc_regs.hfn_mbox + i * sizeof(u32));
 
        /*
         * write 1 to mailbox CMD to trigger LPU event
         */
-       bfa_reg_write(ioc->ioc_regs.hfn_mbox_cmd, 1);
-       (void) bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd);
+       writel(1, ioc->ioc_regs.hfn_mbox_cmd);
+       (void) readl(ioc->ioc_regs.hfn_mbox_cmd);
 }
 
 static void
@@ -1472,7 +1471,7 @@ bfa_ioc_send_enable(struct bfa_ioc_s *ioc)
                    bfa_ioc_portid(ioc));
        enable_req.ioc_class = ioc->ioc_mc;
        bfa_os_gettimeofday(&tv);
-       enable_req.tv_sec = bfa_os_ntohl(tv.tv_sec);
+       enable_req.tv_sec = be32_to_cpu(tv.tv_sec);
        bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req_s));
 }
 
@@ -1503,7 +1502,7 @@ bfa_ioc_hb_check(void *cbarg)
        struct bfa_ioc_s  *ioc = cbarg;
        u32     hb_count;
 
-       hb_count = bfa_reg_read(ioc->ioc_regs.heartbeat);
+       hb_count = readl(ioc->ioc_regs.heartbeat);
        if (ioc->hb_count == hb_count) {
                printk(KERN_CRIT "Firmware heartbeat failure at %d", hb_count);
                bfa_ioc_recover(ioc);
@@ -1519,7 +1518,7 @@ bfa_ioc_hb_check(void *cbarg)
 static void
 bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc)
 {
-       ioc->hb_count = bfa_reg_read(ioc->ioc_regs.heartbeat);
+       ioc->hb_count = readl(ioc->ioc_regs.heartbeat);
        bfa_hb_timer_start(ioc);
 }
 
@@ -1530,7 +1529,7 @@ bfa_ioc_hb_stop(struct bfa_ioc_s *ioc)
 }
 
 
-/**
+/*
  *     Initiate a full firmware download.
  */
 static void
@@ -1543,7 +1542,7 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type,
        u32 chunkno = 0;
        u32 i;
 
-       /**
+       /*
         * Initialize LMEM first before code download
         */
        bfa_ioc_lmem_init(ioc);
@@ -1554,7 +1553,7 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type,
        pgnum = bfa_ioc_smem_pgnum(ioc, loff);
        pgoff = bfa_ioc_smem_pgoff(ioc, loff);
 
-       bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+       writel(pgnum, ioc->ioc_regs.host_page_num_fn);
 
        for (i = 0; i < bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)); i++) {
 
@@ -1564,7 +1563,7 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type,
                                        BFA_IOC_FLASH_CHUNK_ADDR(chunkno));
                }
 
-               /**
+               /*
                 * write smem
                 */
                bfa_mem_write(ioc->ioc_regs.smem_page_start, loff,
@@ -1572,27 +1571,25 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type,
 
                loff += sizeof(u32);
 
-               /**
+               /*
                 * handle page offset wrap around
                 */
                loff = PSS_SMEM_PGOFF(loff);
                if (loff == 0) {
                        pgnum++;
-                       bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
-                                     pgnum);
+                       writel(pgnum, ioc->ioc_regs.host_page_num_fn);
                }
        }
 
-       bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
-                     bfa_ioc_smem_pgnum(ioc, 0));
+       writel(bfa_ioc_smem_pgnum(ioc, 0), ioc->ioc_regs.host_page_num_fn);
 
        /*
         * Set boot type and boot param at the end.
        */
        bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_BOOT_TYPE_OFF,
-                       bfa_os_swap32(boot_type));
+                       swab32(boot_type));
        bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_BOOT_LOADER_OFF,
-                       bfa_os_swap32(boot_env));
+                       swab32(boot_env));
 }
 
 static void
@@ -1601,7 +1598,7 @@ bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force)
        bfa_ioc_hwinit(ioc, force);
 }
 
-/**
+/*
  * Update BFA configuration from firmware configuration.
  */
 static void
@@ -1609,14 +1606,14 @@ bfa_ioc_getattr_reply(struct bfa_ioc_s *ioc)
 {
        struct bfi_ioc_attr_s   *attr = ioc->attr;
 
-       attr->adapter_prop  = bfa_os_ntohl(attr->adapter_prop);
-       attr->card_type     = bfa_os_ntohl(attr->card_type);
-       attr->maxfrsize     = bfa_os_ntohs(attr->maxfrsize);
+       attr->adapter_prop  = be32_to_cpu(attr->adapter_prop);
+       attr->card_type     = be32_to_cpu(attr->card_type);
+       attr->maxfrsize     = be16_to_cpu(attr->maxfrsize);
 
        bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR);
 }
 
-/**
+/*
  * Attach time initialization of mbox logic.
  */
 static void
@@ -1632,7 +1629,7 @@ bfa_ioc_mbox_attach(struct bfa_ioc_s *ioc)
        }
 }
 
-/**
+/*
  * Mbox poll timer -- restarts any pending mailbox requests.
  */
 static void
@@ -1642,27 +1639,27 @@ bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc)
        struct bfa_mbox_cmd_s           *cmd;
        u32                     stat;
 
-       /**
+       /*
         * If no command pending, do nothing
         */
        if (list_empty(&mod->cmd_q))
                return;
 
-       /**
+       /*
         * If previous command is not yet fetched by firmware, do nothing
         */
-       stat = bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd);
+       stat = readl(ioc->ioc_regs.hfn_mbox_cmd);
        if (stat)
                return;
 
-       /**
+       /*
         * Enqueue command to firmware.
         */
        bfa_q_deq(&mod->cmd_q, &cmd);
        bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
 }
 
-/**
+/*
  * Cleanup any pending requests.
  */
 static void
@@ -1675,7 +1672,7 @@ bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc)
                bfa_q_deq(&mod->cmd_q, &cmd);
 }
 
-/**
+/*
  * Read data from SMEM to host through PCI memmap
  *
  * @param[in]  ioc     memory for IOC
@@ -1704,26 +1701,25 @@ bfa_ioc_smem_read(struct bfa_ioc_s *ioc, void *tbuf, u32 soff, u32 sz)
                return BFA_STATUS_FAILED;
        }
 
-       bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+       writel(pgnum, ioc->ioc_regs.host_page_num_fn);
 
        len = sz/sizeof(u32);
        bfa_trc(ioc, len);
        for (i = 0; i < len; i++) {
                r32 = bfa_mem_read(ioc->ioc_regs.smem_page_start, loff);
-               buf[i] = bfa_os_ntohl(r32);
+               buf[i] = be32_to_cpu(r32);
                loff += sizeof(u32);
 
-               /**
+               /*
                 * handle page offset wrap around
                 */
                loff = PSS_SMEM_PGOFF(loff);
                if (loff == 0) {
                        pgnum++;
-                       bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+                       writel(pgnum, ioc->ioc_regs.host_page_num_fn);
                }
        }
-       bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
-                     bfa_ioc_smem_pgnum(ioc, 0));
+       writel(bfa_ioc_smem_pgnum(ioc, 0), ioc->ioc_regs.host_page_num_fn);
        /*
         *  release semaphore.
         */
@@ -1733,7 +1729,7 @@ bfa_ioc_smem_read(struct bfa_ioc_s *ioc, void *tbuf, u32 soff, u32 sz)
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  * Clear SMEM data from host through PCI memmap
  *
  * @param[in]  ioc     memory for IOC
@@ -1760,7 +1756,7 @@ bfa_ioc_smem_clr(struct bfa_ioc_s *ioc, u32 soff, u32 sz)
                return BFA_STATUS_FAILED;
        }
 
-       bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+       writel(pgnum, ioc->ioc_regs.host_page_num_fn);
 
        len = sz/sizeof(u32); /* len in words */
        bfa_trc(ioc, len);
@@ -1768,17 +1764,16 @@ bfa_ioc_smem_clr(struct bfa_ioc_s *ioc, u32 soff, u32 sz)
                bfa_mem_write(ioc->ioc_regs.smem_page_start, loff, 0);
                loff += sizeof(u32);
 
-               /**
+               /*
                 * handle page offset wrap around
                 */
                loff = PSS_SMEM_PGOFF(loff);
                if (loff == 0) {
                        pgnum++;
-                       bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+                       writel(pgnum, ioc->ioc_regs.host_page_num_fn);
                }
        }
-       bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
-                     bfa_ioc_smem_pgnum(ioc, 0));
+       writel(bfa_ioc_smem_pgnum(ioc, 0), ioc->ioc_regs.host_page_num_fn);
 
        /*
         *  release semaphore.
@@ -1788,7 +1783,7 @@ bfa_ioc_smem_clr(struct bfa_ioc_s *ioc, u32 soff, u32 sz)
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  * hal iocpf to ioc interface
  */
 static void
@@ -1813,7 +1808,7 @@ static void
 bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc)
 {
        struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;
-       /**
+       /*
         * Provide enable completion callback.
         */
        ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
@@ -1824,7 +1819,7 @@ bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc)
 
 
 
-/**
+/*
  *  hal_ioc_public
  */
 
@@ -1848,43 +1843,43 @@ bfa_ioc_pll_init(struct bfa_ioc_s *ioc)
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  * Interface used by diag module to do firmware boot with memory test
  * as the entry vector.
  */
 void
 bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_env)
 {
-       bfa_os_addr_t   rb;
+       void __iomem *rb;
 
        bfa_ioc_stats(ioc, ioc_boots);
 
        if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK)
                return;
 
-       /**
+       /*
         * Initialize IOC state of all functions on a chip reset.
         */
        rb = ioc->pcidev.pci_bar_kva;
        if (boot_type == BFI_BOOT_TYPE_MEMTEST) {
-               bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_MEMTEST);
-               bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_MEMTEST);
+               writel(BFI_IOC_MEMTEST, (rb + BFA_IOC0_STATE_REG));
+               writel(BFI_IOC_MEMTEST, (rb + BFA_IOC1_STATE_REG));
        } else {
-               bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_INITING);
-               bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_INITING);
+               writel(BFI_IOC_INITING, (rb + BFA_IOC0_STATE_REG));
+               writel(BFI_IOC_INITING, (rb + BFA_IOC1_STATE_REG));
        }
 
        bfa_ioc_msgflush(ioc);
        bfa_ioc_download_fw(ioc, boot_type, boot_env);
 
-       /**
+       /*
         * Enable interrupts just before starting LPU
         */
        ioc->cbfn->reset_cbfn(ioc->bfa);
        bfa_ioc_lpu_start(ioc);
 }
 
-/**
+/*
  * Enable/disable IOC failure auto recovery.
  */
 void
@@ -1904,7 +1899,7 @@ bfa_ioc_is_operational(struct bfa_ioc_s *ioc)
 bfa_boolean_t
 bfa_ioc_is_initialized(struct bfa_ioc_s *ioc)
 {
-       u32 r32 = bfa_reg_read(ioc->ioc_regs.ioc_fwstate);
+       u32 r32 = readl(ioc->ioc_regs.ioc_fwstate);
 
        return ((r32 != BFI_IOC_UNINIT) &&
                (r32 != BFI_IOC_INITING) &&
@@ -1918,21 +1913,21 @@ bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg)
        u32     r32;
        int             i;
 
-       /**
+       /*
         * read the MBOX msg
         */
        for (i = 0; i < (sizeof(union bfi_ioc_i2h_msg_u) / sizeof(u32));
             i++) {
-               r32 = bfa_reg_read(ioc->ioc_regs.lpu_mbox +
+               r32 = readl(ioc->ioc_regs.lpu_mbox +
                                   i * sizeof(u32));
-               msgp[i] = bfa_os_htonl(r32);
+               msgp[i] = cpu_to_be32(r32);
        }
 
-       /**
+       /*
         * turn off mailbox interrupt by clearing mailbox status
         */
-       bfa_reg_write(ioc->ioc_regs.lpu_mbox_cmd, 1);
-       bfa_reg_read(ioc->ioc_regs.lpu_mbox_cmd);
+       writel(1, ioc->ioc_regs.lpu_mbox_cmd);
+       readl(ioc->ioc_regs.lpu_mbox_cmd);
 }
 
 void
@@ -1971,7 +1966,7 @@ bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *m)
        }
 }
 
-/**
+/*
  * IOC attach time initialization and setup.
  *
  * @param[in]  ioc     memory for IOC
@@ -1996,7 +1991,7 @@ bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, struct bfa_ioc_cbfn_s *cbfn,
        bfa_fsm_send_event(ioc, IOC_E_RESET);
 }
 
-/**
+/*
  * Driver detach time IOC cleanup.
  */
 void
@@ -2005,7 +2000,7 @@ bfa_ioc_detach(struct bfa_ioc_s *ioc)
        bfa_fsm_send_event(ioc, IOC_E_DETACH);
 }
 
-/**
+/*
  * Setup IOC PCI properties.
  *
  * @param[in]  pcidev  PCI device information for this IOC
@@ -2019,7 +2014,7 @@ bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,
        ioc->ctdev      = bfa_asic_id_ct(ioc->pcidev.device_id);
        ioc->cna        = ioc->ctdev && !ioc->fcmode;
 
-       /**
+       /*
         * Set asic specific interfaces. See bfa_ioc_cb.c and bfa_ioc_ct.c
         */
        if (ioc->ctdev)
@@ -2031,7 +2026,7 @@ bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,
        bfa_ioc_reg_init(ioc);
 }
 
-/**
+/*
  * Initialize IOC dma memory
  *
  * @param[in]  dm_kva  kernel virtual address of IOC dma memory
@@ -2040,7 +2035,7 @@ bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,
 void
 bfa_ioc_mem_claim(struct bfa_ioc_s *ioc,  u8 *dm_kva, u64 dm_pa)
 {
-       /**
+       /*
         * dma memory for firmware attribute
         */
        ioc->attr_dma.kva = dm_kva;
@@ -2048,7 +2043,7 @@ bfa_ioc_mem_claim(struct bfa_ioc_s *ioc,  u8 *dm_kva, u64 dm_pa)
        ioc->attr = (struct bfi_ioc_attr_s *) dm_kva;
 }
 
-/**
+/*
  * Return size of dma memory required.
  */
 u32
@@ -2073,7 +2068,7 @@ bfa_ioc_disable(struct bfa_ioc_s *ioc)
        bfa_fsm_send_event(ioc, IOC_E_DISABLE);
 }
 
-/**
+/*
  * Returns memory required for saving firmware trace in case of crash.
  * Driver must call this interface to allocate memory required for
  * automatic saving of firmware trace. Driver should call
@@ -2086,7 +2081,7 @@ bfa_ioc_debug_trcsz(bfa_boolean_t auto_recover)
        return (auto_recover) ? BFA_DBG_FWTRC_LEN : 0;
 }
 
-/**
+/*
  * Initialize memory for saving firmware trace. Driver must initialize
  * trace memory before call bfa_ioc_enable().
  */
@@ -2109,7 +2104,7 @@ bfa_ioc_smem_pgoff(struct bfa_ioc_s *ioc, u32 fmaddr)
        return PSS_SMEM_PGOFF(fmaddr);
 }
 
-/**
+/*
  * Register mailbox message handler functions
  *
  * @param[in]  ioc             IOC instance
@@ -2125,7 +2120,7 @@ bfa_ioc_mbox_register(struct bfa_ioc_s *ioc, bfa_ioc_mbox_mcfunc_t *mcfuncs)
                mod->mbhdlr[mc].cbfn = mcfuncs[mc];
 }
 
-/**
+/*
  * Register mailbox message handler function, to be called by common modules
  */
 void
@@ -2138,7 +2133,7 @@ bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc,
        mod->mbhdlr[mc].cbarg   = cbarg;
 }
 
-/**
+/*
  * Queue a mailbox command request to firmware. Waits if mailbox is busy.
  * Responsibility of caller to serialize
  *
@@ -2151,7 +2146,7 @@ bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd)
        struct bfa_ioc_mbox_mod_s       *mod = &ioc->mbox_mod;
        u32                     stat;
 
-       /**
+       /*
         * If a previous command is pending, queue new command
         */
        if (!list_empty(&mod->cmd_q)) {
@@ -2159,22 +2154,22 @@ bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd)
                return;
        }
 
-       /**
+       /*
         * If mailbox is busy, queue command for poll timer
         */
-       stat = bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd);
+       stat = readl(ioc->ioc_regs.hfn_mbox_cmd);
        if (stat) {
                list_add_tail(&cmd->qe, &mod->cmd_q);
                return;
        }
 
-       /**
+       /*
         * mailbox is free -- queue command to firmware
         */
        bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
 }
 
-/**
+/*
  * Handle mailbox interrupts
  */
 void
@@ -2186,7 +2181,7 @@ bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc)
 
        bfa_ioc_msgget(ioc, &m);
 
-       /**
+       /*
         * Treat IOC message class as special.
         */
        mc = m.mh.msg_class;
@@ -2214,7 +2209,7 @@ bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc)
        ioc->port_id = bfa_ioc_pcifn(ioc);
 }
 
-/**
+/*
  * return true if IOC is disabled
  */
 bfa_boolean_t
@@ -2224,7 +2219,7 @@ bfa_ioc_is_disabled(struct bfa_ioc_s *ioc)
                bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled);
 }
 
-/**
+/*
  * return true if IOC firmware is different.
  */
 bfa_boolean_t
@@ -2243,7 +2238,7 @@ bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc)
         ((__sm) == BFI_IOC_FAIL) ||            \
         ((__sm) == BFI_IOC_CFG_DISABLED))
 
-/**
+/*
  * Check if adapter is disabled -- both IOCs should be in a disabled
  * state.
  */
@@ -2251,17 +2246,17 @@ bfa_boolean_t
 bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc)
 {
        u32     ioc_state;
-       bfa_os_addr_t   rb = ioc->pcidev.pci_bar_kva;
+       void __iomem *rb = ioc->pcidev.pci_bar_kva;
 
        if (!bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled))
                return BFA_FALSE;
 
-       ioc_state = bfa_reg_read(rb + BFA_IOC0_STATE_REG);
+       ioc_state = readl(rb + BFA_IOC0_STATE_REG);
        if (!bfa_ioc_state_disabled(ioc_state))
                return BFA_FALSE;
 
        if (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_FC_8G1P) {
-               ioc_state = bfa_reg_read(rb + BFA_IOC1_STATE_REG);
+               ioc_state = readl(rb + BFA_IOC1_STATE_REG);
                if (!bfa_ioc_state_disabled(ioc_state))
                        return BFA_FALSE;
        }
@@ -2269,7 +2264,7 @@ bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc)
        return BFA_TRUE;
 }
 
-/**
+/*
  * Add to IOC heartbeat failure notification queue. To be used by common
  * modules such as cee, port, diag.
  */
@@ -2293,7 +2288,7 @@ bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
        bfa_ioc_get_adapter_fw_ver(ioc, ad_attr->fw_ver);
        bfa_ioc_get_adapter_optrom_ver(ioc, ad_attr->optrom_ver);
        bfa_ioc_get_adapter_manufacturer(ioc, ad_attr->manufacturer);
-       bfa_os_memcpy(&ad_attr->vpd, &ioc_attr->vpd,
+       memcpy(&ad_attr->vpd, &ioc_attr->vpd,
                      sizeof(struct bfa_mfg_vpd_s));
 
        ad_attr->nports = bfa_ioc_get_nports(ioc);
@@ -2343,8 +2338,8 @@ bfa_ioc_get_type(struct bfa_ioc_s *ioc)
 void
 bfa_ioc_get_adapter_serial_num(struct bfa_ioc_s *ioc, char *serial_num)
 {
-       bfa_os_memset((void *)serial_num, 0, BFA_ADAPTER_SERIAL_NUM_LEN);
-       bfa_os_memcpy((void *)serial_num,
+       memset((void *)serial_num, 0, BFA_ADAPTER_SERIAL_NUM_LEN);
+       memcpy((void *)serial_num,
                        (void *)ioc->attr->brcd_serialnum,
                        BFA_ADAPTER_SERIAL_NUM_LEN);
 }
@@ -2352,8 +2347,8 @@ bfa_ioc_get_adapter_serial_num(struct bfa_ioc_s *ioc, char *serial_num)
 void
 bfa_ioc_get_adapter_fw_ver(struct bfa_ioc_s *ioc, char *fw_ver)
 {
-       bfa_os_memset((void *)fw_ver, 0, BFA_VERSION_LEN);
-       bfa_os_memcpy(fw_ver, ioc->attr->fw_version, BFA_VERSION_LEN);
+       memset((void *)fw_ver, 0, BFA_VERSION_LEN);
+       memcpy(fw_ver, ioc->attr->fw_version, BFA_VERSION_LEN);
 }
 
 void
@@ -2361,7 +2356,7 @@ bfa_ioc_get_pci_chip_rev(struct bfa_ioc_s *ioc, char *chip_rev)
 {
        bfa_assert(chip_rev);
 
-       bfa_os_memset((void *)chip_rev, 0, BFA_IOC_CHIP_REV_LEN);
+       memset((void *)chip_rev, 0, BFA_IOC_CHIP_REV_LEN);
 
        chip_rev[0] = 'R';
        chip_rev[1] = 'e';
@@ -2374,16 +2369,16 @@ bfa_ioc_get_pci_chip_rev(struct bfa_ioc_s *ioc, char *chip_rev)
 void
 bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc_s *ioc, char *optrom_ver)
 {
-       bfa_os_memset((void *)optrom_ver, 0, BFA_VERSION_LEN);
-       bfa_os_memcpy(optrom_ver, ioc->attr->optrom_version,
+       memset((void *)optrom_ver, 0, BFA_VERSION_LEN);
+       memcpy(optrom_ver, ioc->attr->optrom_version,
                      BFA_VERSION_LEN);
 }
 
 void
 bfa_ioc_get_adapter_manufacturer(struct bfa_ioc_s *ioc, char *manufacturer)
 {
-       bfa_os_memset((void *)manufacturer, 0, BFA_ADAPTER_MFG_NAME_LEN);
-       bfa_os_memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
+       memset((void *)manufacturer, 0, BFA_ADAPTER_MFG_NAME_LEN);
+       memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
 }
 
 void
@@ -2392,14 +2387,14 @@ bfa_ioc_get_adapter_model(struct bfa_ioc_s *ioc, char *model)
        struct bfi_ioc_attr_s   *ioc_attr;
 
        bfa_assert(model);
-       bfa_os_memset((void *)model, 0, BFA_ADAPTER_MODEL_NAME_LEN);
+       memset((void *)model, 0, BFA_ADAPTER_MODEL_NAME_LEN);
 
        ioc_attr = ioc->attr;
 
-       /**
+       /*
         * model name
         */
-       bfa_os_snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u",
+       snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u",
                BFA_MFG_NAME, ioc_attr->card_type);
 }
 
@@ -2446,7 +2441,7 @@ bfa_ioc_get_state(struct bfa_ioc_s *ioc)
 void
 bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr)
 {
-       bfa_os_memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr_s));
+       memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr_s));
 
        ioc_attr->state = bfa_ioc_get_state(ioc);
        ioc_attr->port_id = ioc->port_id;
@@ -2460,7 +2455,7 @@ bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr)
        bfa_ioc_get_pci_chip_rev(ioc, ioc_attr->pci_attr.chip_rev);
 }
 
-/**
+/*
  *  hal_wwn_public
  */
 wwn_t
@@ -2526,7 +2521,7 @@ bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc)
        return ioc->fcmode || !bfa_asic_id_ct(ioc->pcidev.device_id);
 }
 
-/**
+/*
  * Retrieve saved firmware trace from a prior IOC failure.
  */
 bfa_status_t
@@ -2541,12 +2536,12 @@ bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata, int *trclen)
        if (tlen > ioc->dbg_fwsave_len)
                tlen = ioc->dbg_fwsave_len;
 
-       bfa_os_memcpy(trcdata, ioc->dbg_fwsave, tlen);
+       memcpy(trcdata, ioc->dbg_fwsave, tlen);
        *trclen = tlen;
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  * Clear saved firmware trace
  */
 void
@@ -2555,7 +2550,7 @@ bfa_ioc_debug_fwsave_clear(struct bfa_ioc_s *ioc)
        ioc->dbg_fwsave_once = BFA_TRUE;
 }
 
-/**
+/*
  * Retrieve saved firmware trace from a prior IOC failure.
  */
 bfa_status_t
@@ -2595,7 +2590,7 @@ bfa_ioc_fwsync(struct bfa_ioc_s *ioc)
 
        bfa_ioc_send_fwsync(ioc);
 
-       /**
+       /*
         * After sending a fw sync mbox command wait for it to
         * take effect.  We will not wait for a response because
         *    1. fw_sync mbox cmd doesn't have a response.
@@ -2610,7 +2605,7 @@ bfa_ioc_fwsync(struct bfa_ioc_s *ioc)
                fwsync_iter--;
 }
 
-/**
+/*
  * Dump firmware smem
  */
 bfa_status_t
@@ -2630,7 +2625,7 @@ bfa_ioc_debug_fwcore(struct bfa_ioc_s *ioc, void *buf,
        loff = *offset;
        dlen = *buflen;
 
-       /**
+       /*
         * First smem read, sync smem before proceeding
         * No need to sync before reading every chunk.
         */
@@ -2657,7 +2652,7 @@ bfa_ioc_debug_fwcore(struct bfa_ioc_s *ioc, void *buf,
        return status;
 }
 
-/**
+/*
  * Firmware statistics
  */
 bfa_status_t
@@ -2702,7 +2697,7 @@ bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc)
        return status;
 }
 
-/**
+/*
  * Save firmware trace if configured.
  */
 static void
@@ -2716,7 +2711,7 @@ bfa_ioc_debug_save(struct bfa_ioc_s *ioc)
        }
 }
 
-/**
+/*
  * Firmware failure detected. Start recovery actions.
  */
 static void
@@ -2738,7 +2733,7 @@ bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc)
                return;
 }
 
-/**
+/*
  *  hal_iocpf_pvt BFA IOC PF private functions
  */
 
@@ -2795,7 +2790,7 @@ bfa_iocpf_sem_timeout(void *ioc_arg)
        bfa_ioc_hw_sem_get(ioc);
 }
 
-/**
+/*
  *  bfa timer function
  */
 void
@@ -2840,7 +2835,7 @@ bfa_timer_beat(struct bfa_timer_mod_s *mod)
        }
 }
 
-/**
+/*
  * Should be called with lock protection
  */
 void
@@ -2858,7 +2853,7 @@ bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer,
        list_add_tail(&timer->qe, &mod->timer_q);
 }
 
-/**
+/*
  * Should be called with lock protection
  */
 void
index 288c5801aace553021d68472824f342ce9aac0e0..9c407a87a1a1e01e228531c5dd48a4a0f1c85f3b 100644 (file)
 #include "bfa_cs.h"
 #include "bfi.h"
 
-/**
+/*
  * BFA timer declarations
  */
 typedef void (*bfa_timer_cbfn_t)(void *);
 
-/**
+/*
  * BFA timer data structure
  */
 struct bfa_timer_s {
        struct list_head        qe;
        bfa_timer_cbfn_t timercb;
        void            *arg;
-       int             timeout;        /**< in millisecs. */
+       int             timeout;        /* in millisecs */
 };
 
-/**
+/*
  * Timer module structure
  */
 struct bfa_timer_mod_s {
        struct list_head timer_q;
 };
 
-#define BFA_TIMER_FREQ 200 /**< specified in millisecs */
+#define BFA_TIMER_FREQ 200 /* specified in millisecs */
 
 void bfa_timer_beat(struct bfa_timer_mod_s *mod);
 void bfa_timer_init(struct bfa_timer_mod_s *mod);
@@ -53,7 +53,7 @@ void bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer,
                        unsigned int timeout);
 void bfa_timer_stop(struct bfa_timer_s *timer);
 
-/**
+/*
  * Generic Scatter Gather Element used by driver
  */
 struct bfa_sge_s {
@@ -62,9 +62,9 @@ struct bfa_sge_s {
 };
 
 #define bfa_sge_word_swap(__sge) do {                                       \
-       ((u32 *)(__sge))[0] = bfa_os_swap32(((u32 *)(__sge))[0]);      \
-       ((u32 *)(__sge))[1] = bfa_os_swap32(((u32 *)(__sge))[1]);      \
-       ((u32 *)(__sge))[2] = bfa_os_swap32(((u32 *)(__sge))[2]);      \
+       ((u32 *)(__sge))[0] = swab32(((u32 *)(__sge))[0]);      \
+       ((u32 *)(__sge))[1] = swab32(((u32 *)(__sge))[1]);      \
+       ((u32 *)(__sge))[2] = swab32(((u32 *)(__sge))[2]);      \
 } while (0)
 
 #define bfa_swap_words(_x)  (  \
@@ -80,17 +80,17 @@ struct bfa_sge_s {
 #define bfa_sgaddr_le(_x)      (_x)
 #endif
 
-/**
+/*
  * PCI device information required by IOC
  */
 struct bfa_pcidev_s {
        int             pci_slot;
        u8              pci_func;
-       u16     device_id;
-       bfa_os_addr_t   pci_bar_kva;
+       u16             device_id;
+       void __iomem    *pci_bar_kva;
 };
 
-/**
+/*
  * Structure used to remember the DMA-able memory block's KVA and Physical
  * Address
  */
@@ -102,7 +102,7 @@ struct bfa_dma_s {
 #define BFA_DMA_ALIGN_SZ       256
 #define BFA_ROUNDUP(_l, _s)    (((_l) + ((_s) - 1)) & ~((_s) - 1))
 
-/**
+/*
  * smem size for Crossbow and Catapult
  */
 #define BFI_SMEM_CB_SIZE       0x200000U       /* ! 2MB for crossbow   */
@@ -125,40 +125,38 @@ __bfa_dma_addr_set(union bfi_addr_u *dma_addr, u64 pa)
 static inline void
 __bfa_dma_be_addr_set(union bfi_addr_u *dma_addr, u64 pa)
 {
-       dma_addr->a32.addr_lo = (u32) bfa_os_htonl(pa);
-       dma_addr->a32.addr_hi = (u32) bfa_os_htonl(bfa_os_u32(pa));
+       dma_addr->a32.addr_lo = (u32) cpu_to_be32(pa);
+       dma_addr->a32.addr_hi = (u32) cpu_to_be32(bfa_os_u32(pa));
 }
 
 struct bfa_ioc_regs_s {
-       bfa_os_addr_t   hfn_mbox_cmd;
-       bfa_os_addr_t   hfn_mbox;
-       bfa_os_addr_t   lpu_mbox_cmd;
-       bfa_os_addr_t   lpu_mbox;
-       bfa_os_addr_t   pss_ctl_reg;
-       bfa_os_addr_t   pss_err_status_reg;
-       bfa_os_addr_t   app_pll_fast_ctl_reg;
-       bfa_os_addr_t   app_pll_slow_ctl_reg;
-       bfa_os_addr_t   ioc_sem_reg;
-       bfa_os_addr_t   ioc_usage_sem_reg;
-       bfa_os_addr_t   ioc_init_sem_reg;
-       bfa_os_addr_t   ioc_usage_reg;
-       bfa_os_addr_t   host_page_num_fn;
-       bfa_os_addr_t   heartbeat;
-       bfa_os_addr_t   ioc_fwstate;
-       bfa_os_addr_t   ll_halt;
-       bfa_os_addr_t   err_set;
-       bfa_os_addr_t   shirq_isr_next;
-       bfa_os_addr_t   shirq_msk_next;
-       bfa_os_addr_t   smem_page_start;
+       void __iomem *hfn_mbox_cmd;
+       void __iomem *hfn_mbox;
+       void __iomem *lpu_mbox_cmd;
+       void __iomem *lpu_mbox;
+       void __iomem *pss_ctl_reg;
+       void __iomem *pss_err_status_reg;
+       void __iomem *app_pll_fast_ctl_reg;
+       void __iomem *app_pll_slow_ctl_reg;
+       void __iomem *ioc_sem_reg;
+       void __iomem *ioc_usage_sem_reg;
+       void __iomem *ioc_init_sem_reg;
+       void __iomem *ioc_usage_reg;
+       void __iomem *host_page_num_fn;
+       void __iomem *heartbeat;
+       void __iomem *ioc_fwstate;
+       void __iomem *ll_halt;
+       void __iomem *err_set;
+       void __iomem *shirq_isr_next;
+       void __iomem *shirq_msk_next;
+       void __iomem *smem_page_start;
        u32     smem_pg0;
 };
 
-#define bfa_reg_read(_raddr)   bfa_os_reg_read(_raddr)
-#define bfa_reg_write(_raddr, _val)    bfa_os_reg_write(_raddr, _val)
-#define bfa_mem_read(_raddr, _off)     bfa_os_mem_read(_raddr, _off)
+#define bfa_mem_read(_raddr, _off)     swab32(readl(((_raddr) + (_off))))
 #define bfa_mem_write(_raddr, _off, _val)      \
-                                       bfa_os_mem_write(_raddr, _off, _val)
-/**
+                       writel(swab32((_val)), ((_raddr) + (_off)))
+/*
  * IOC Mailbox structures
  */
 struct bfa_mbox_cmd_s {
@@ -166,7 +164,7 @@ struct bfa_mbox_cmd_s {
        u32     msg[BFI_IOC_MSGSZ];
 };
 
-/**
+/*
  * IOC mailbox module
  */
 typedef void (*bfa_ioc_mbox_mcfunc_t)(void *cbarg, struct bfi_mbmsg_s *m);
@@ -179,7 +177,7 @@ struct bfa_ioc_mbox_mod_s {
        } mbhdlr[BFI_MC_MAX];
 };
 
-/**
+/*
  * IOC callback function interfaces
  */
 typedef void (*bfa_ioc_enable_cbfn_t)(void *bfa, enum bfa_status status);
@@ -193,7 +191,7 @@ struct bfa_ioc_cbfn_s {
        bfa_ioc_reset_cbfn_t    reset_cbfn;
 };
 
-/**
+/*
  * Heartbeat failure notification queue element.
  */
 struct bfa_ioc_hbfail_notify_s {
@@ -202,7 +200,7 @@ struct bfa_ioc_hbfail_notify_s {
        void                    *cbarg;
 };
 
-/**
+/*
  * Initialize a heartbeat failure notification structure
  */
 #define bfa_ioc_hbfail_init(__notify, __cbfn, __cbarg) do {    \
@@ -249,7 +247,7 @@ struct bfa_ioc_s {
 };
 
 struct bfa_ioc_hwif_s {
-       bfa_status_t (*ioc_pll_init) (bfa_os_addr_t rb, bfa_boolean_t fcmode);
+       bfa_status_t (*ioc_pll_init) (void __iomem *rb, bfa_boolean_t fcmode);
        bfa_boolean_t   (*ioc_firmware_lock)    (struct bfa_ioc_s *ioc);
        void            (*ioc_firmware_unlock)  (struct bfa_ioc_s *ioc);
        void            (*ioc_reg_init) (struct bfa_ioc_s *ioc);
@@ -267,7 +265,7 @@ struct bfa_ioc_hwif_s {
 #define bfa_ioc_fetch_stats(__ioc, __stats) \
                (((__stats)->drv_stats) = (__ioc)->stats)
 #define bfa_ioc_clr_stats(__ioc)       \
-               bfa_os_memset(&(__ioc)->stats, 0, sizeof((__ioc)->stats))
+               memset(&(__ioc)->stats, 0, sizeof((__ioc)->stats))
 #define bfa_ioc_maxfrsize(__ioc)       ((__ioc)->attr->maxfrsize)
 #define bfa_ioc_rx_bbcredit(__ioc)     ((__ioc)->attr->rx_bbcredit)
 #define bfa_ioc_speed_sup(__ioc)       \
@@ -287,7 +285,7 @@ struct bfa_ioc_hwif_s {
 #define BFA_IOC_FLASH_OFFSET_IN_CHUNK(off)     (off % BFI_FLASH_CHUNK_SZ_WORDS)
 #define BFA_IOC_FLASH_CHUNK_ADDR(chunkno)  (chunkno * BFI_FLASH_CHUNK_SZ_WORDS)
 
-/**
+/*
  * IOC mailbox interface
  */
 void bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd);
@@ -299,7 +297,7 @@ void bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg);
 void bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc,
                bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg);
 
-/**
+/*
  * IOC interfaces
  */
 
@@ -308,9 +306,9 @@ void bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc,
                           (__ioc)->fcmode))
 
 bfa_status_t bfa_ioc_pll_init(struct bfa_ioc_s *ioc);
-bfa_status_t bfa_ioc_cb_pll_init(bfa_os_addr_t rb, bfa_boolean_t fcmode);
-bfa_boolean_t bfa_ioc_ct_pll_init_complete(bfa_os_addr_t rb);
-bfa_status_t bfa_ioc_ct_pll_init(bfa_os_addr_t rb, bfa_boolean_t fcmode);
+bfa_status_t bfa_ioc_cb_pll_init(void __iomem *rb, bfa_boolean_t fcmode);
+bfa_boolean_t bfa_ioc_ct_pll_init_complete(void __iomem *rb);
+bfa_status_t bfa_ioc_ct_pll_init(void __iomem *rb, bfa_boolean_t fcmode);
 
 #define        bfa_ioc_isr_mode_set(__ioc, __msix)                     \
                        ((__ioc)->ioc_hwif->ioc_isr_mode_set(__ioc, __msix))
@@ -370,8 +368,8 @@ void bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc);
 bfa_boolean_t bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc);
 void bfa_ioc_hbfail_register(struct bfa_ioc_s *ioc,
        struct bfa_ioc_hbfail_notify_s *notify);
-bfa_boolean_t bfa_ioc_sem_get(bfa_os_addr_t sem_reg);
-void bfa_ioc_sem_release(bfa_os_addr_t sem_reg);
+bfa_boolean_t bfa_ioc_sem_get(void __iomem *sem_reg);
+void bfa_ioc_sem_release(void __iomem *sem_reg);
 void bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc);
 void bfa_ioc_fwver_get(struct bfa_ioc_s *ioc,
                        struct bfi_ioc_image_hdr_s *fwhdr);
@@ -441,7 +439,7 @@ bfa_cb_image_get_size(int type)
        }
 }
 
-/**
+/*
  * CNA TRCMOD declaration
  */
 /*
index d7ac864d8539de35a1fc56c28c33091be71534a9..909945043850fbbeaf5b3a0699fd46e11186bd9e 100644 (file)
@@ -34,7 +34,7 @@ static void bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc);
 
 struct bfa_ioc_hwif_s hwif_cb;
 
-/**
+/*
  * Called from bfa_ioc_attach() to map asic specific calls.
  */
 void
@@ -52,7 +52,7 @@ bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc)
        ioc->ioc_hwif = &hwif_cb;
 }
 
-/**
+/*
  * Return true if firmware of current driver matches the running firmware.
  */
 static bfa_boolean_t
@@ -66,17 +66,17 @@ bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc)
 {
 }
 
-/**
+/*
  * Notify other functions on HB failure.
  */
 static void
 bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc)
 {
-       bfa_reg_write(ioc->ioc_regs.err_set, __PSS_ERR_STATUS_SET);
-       bfa_reg_read(ioc->ioc_regs.err_set);
+       writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set);
+       readl(ioc->ioc_regs.err_set);
 }
 
-/**
+/*
  * Host to LPU mailbox message addresses
  */
 static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = {
@@ -84,7 +84,7 @@ static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = {
        { HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 }
 };
 
-/**
+/*
  * Host <-> LPU mailbox command/status registers
  */
 static struct { u32 hfn, lpu; } iocreg_mbcmd[] = {
@@ -96,7 +96,7 @@ static struct { u32 hfn, lpu; } iocreg_mbcmd[] = {
 static void
 bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc)
 {
-       bfa_os_addr_t   rb;
+       void __iomem *rb;
        int             pcifn = bfa_ioc_pcifn(ioc);
 
        rb = bfa_ioc_bar0(ioc);
@@ -113,7 +113,7 @@ bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc)
                ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
        }
 
-       /**
+       /*
         * Host <-> LPU mailbox command/status registers
         */
        ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd[pcifn].hfn;
@@ -133,7 +133,7 @@ bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc)
        ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG);
        ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG);
 
-       /**
+       /*
         * sram memory access
         */
        ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START);
@@ -145,14 +145,14 @@ bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc)
        ioc->ioc_regs.err_set = (rb + ERR_SET_REG);
 }
 
-/**
+/*
  * Initialize IOC to port mapping.
  */
 
 static void
 bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc)
 {
-       /**
+       /*
         * For crossbow, port id is same as pci function.
         */
        ioc->port_id = bfa_ioc_pcifn(ioc);
@@ -160,7 +160,7 @@ bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc)
        bfa_trc(ioc, ioc->port_id);
 }
 
-/**
+/*
  * Set interrupt mode for a function: INTX or MSIX
  */
 static void
@@ -168,7 +168,7 @@ bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix)
 {
 }
 
-/**
+/*
  * Cleanup hw semaphore and usecnt registers
  */
 static void
@@ -180,14 +180,14 @@ bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc)
         * before we clear it. If it is not locked, writing 1
         * will lock it instead of clearing it.
         */
-       bfa_reg_read(ioc->ioc_regs.ioc_sem_reg);
+       readl(ioc->ioc_regs.ioc_sem_reg);
        bfa_ioc_hw_sem_release(ioc);
 }
 
 
 
 bfa_status_t
-bfa_ioc_cb_pll_init(bfa_os_addr_t rb, bfa_boolean_t fcmode)
+bfa_ioc_cb_pll_init(void __iomem *rb, bfa_boolean_t fcmode)
 {
        u32     pll_sclk, pll_fclk;
 
@@ -199,38 +199,32 @@ bfa_ioc_cb_pll_init(bfa_os_addr_t rb, bfa_boolean_t fcmode)
                __APP_PLL_400_RSEL200500 | __APP_PLL_400_P0_1(3U) |
                __APP_PLL_400_JITLMT0_1(3U) |
                __APP_PLL_400_CNTLMT0_1(3U);
-       bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT);
-       bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT);
-       bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
-       bfa_reg_write(rb + APP_PLL_212_CTL_REG,
-                         __APP_PLL_212_LOGIC_SOFT_RESET);
-       bfa_reg_write(rb + APP_PLL_212_CTL_REG,
-                         __APP_PLL_212_BYPASS |
-                         __APP_PLL_212_LOGIC_SOFT_RESET);
-       bfa_reg_write(rb + APP_PLL_400_CTL_REG,
-                         __APP_PLL_400_LOGIC_SOFT_RESET);
-       bfa_reg_write(rb + APP_PLL_400_CTL_REG,
-                         __APP_PLL_400_BYPASS |
-                         __APP_PLL_400_LOGIC_SOFT_RESET);
-       bfa_os_udelay(2);
-       bfa_reg_write(rb + APP_PLL_212_CTL_REG,
-                         __APP_PLL_212_LOGIC_SOFT_RESET);
-       bfa_reg_write(rb + APP_PLL_400_CTL_REG,
-                         __APP_PLL_400_LOGIC_SOFT_RESET);
-       bfa_reg_write(rb + APP_PLL_212_CTL_REG,
-                         pll_sclk | __APP_PLL_212_LOGIC_SOFT_RESET);
-       bfa_reg_write(rb + APP_PLL_400_CTL_REG,
-                         pll_fclk | __APP_PLL_400_LOGIC_SOFT_RESET);
-       bfa_os_udelay(2000);
-       bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
-       bfa_reg_write((rb + APP_PLL_212_CTL_REG), pll_sclk);
-       bfa_reg_write((rb + APP_PLL_400_CTL_REG), pll_fclk);
+       writel(BFI_IOC_UNINIT, (rb + BFA_IOC0_STATE_REG));
+       writel(BFI_IOC_UNINIT, (rb + BFA_IOC1_STATE_REG));
+       writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
+       writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
+       writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
+       writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS));
+       writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
+       writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
+       writel(__APP_PLL_212_LOGIC_SOFT_RESET, rb + APP_PLL_212_CTL_REG);
+       writel(__APP_PLL_212_BYPASS | __APP_PLL_212_LOGIC_SOFT_RESET,
+                       rb + APP_PLL_212_CTL_REG);
+       writel(__APP_PLL_400_LOGIC_SOFT_RESET, rb + APP_PLL_400_CTL_REG);
+       writel(__APP_PLL_400_BYPASS | __APP_PLL_400_LOGIC_SOFT_RESET,
+                       rb + APP_PLL_400_CTL_REG);
+       udelay(2);
+       writel(__APP_PLL_212_LOGIC_SOFT_RESET, rb + APP_PLL_212_CTL_REG);
+       writel(__APP_PLL_400_LOGIC_SOFT_RESET, rb + APP_PLL_400_CTL_REG);
+       writel(pll_sclk | __APP_PLL_212_LOGIC_SOFT_RESET,
+                       rb + APP_PLL_212_CTL_REG);
+       writel(pll_fclk | __APP_PLL_400_LOGIC_SOFT_RESET,
+                       rb + APP_PLL_400_CTL_REG);
+       udelay(2000);
+       writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
+       writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS));
+       writel(pll_sclk, (rb + APP_PLL_212_CTL_REG));
+       writel(pll_fclk, (rb + APP_PLL_400_CTL_REG));
 
        return BFA_STATUS_OK;
 }
index f21b82c5f64c64cf271b378099d38484dbf2611c..115730c0aa77f321aa25ee6f0d7136f43c8c2b90 100644 (file)
@@ -34,7 +34,7 @@ static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc);
 
 struct bfa_ioc_hwif_s hwif_ct;
 
-/**
+/*
  * Called from bfa_ioc_attach() to map asic specific calls.
  */
 void
@@ -52,7 +52,7 @@ bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc)
        ioc->ioc_hwif = &hwif_ct;
 }
 
-/**
+/*
  * Return true if firmware of current driver matches the running firmware.
  */
 static bfa_boolean_t
@@ -62,13 +62,13 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc)
        u32 usecnt;
        struct bfi_ioc_image_hdr_s fwhdr;
 
-       /**
+       /*
         * Firmware match check is relevant only for CNA.
         */
        if (!ioc->cna)
                return BFA_TRUE;
 
-       /**
+       /*
         * If bios boot (flash based) -- do not increment usage count
         */
        if (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) <
@@ -76,27 +76,27 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc)
                return BFA_TRUE;
 
        bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
-       usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg);
+       usecnt = readl(ioc->ioc_regs.ioc_usage_reg);
 
-       /**
+       /*
         * If usage count is 0, always return TRUE.
         */
        if (usecnt == 0) {
-               bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, 1);
+               writel(1, ioc->ioc_regs.ioc_usage_reg);
                bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
                bfa_trc(ioc, usecnt);
                return BFA_TRUE;
        }
 
-       ioc_fwstate = bfa_reg_read(ioc->ioc_regs.ioc_fwstate);
+       ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate);
        bfa_trc(ioc, ioc_fwstate);
 
-       /**
+       /*
         * Use count cannot be non-zero and chip in uninitialized state.
         */
        bfa_assert(ioc_fwstate != BFI_IOC_UNINIT);
 
-       /**
+       /*
         * Check if another driver with a different firmware is active
         */
        bfa_ioc_fwver_get(ioc, &fwhdr);
@@ -106,11 +106,11 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc)
                return BFA_FALSE;
        }
 
-       /**
+       /*
         * Same firmware version. Increment the reference count.
         */
        usecnt++;
-       bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt);
+       writel(usecnt, ioc->ioc_regs.ioc_usage_reg);
        bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
        bfa_trc(ioc, usecnt);
        return BFA_TRUE;
@@ -121,50 +121,50 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc)
 {
        u32 usecnt;
 
-       /**
+       /*
         * Firmware lock is relevant only for CNA.
         */
        if (!ioc->cna)
                return;
 
-       /**
+       /*
         * If bios boot (flash based) -- do not decrement usage count
         */
        if (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) <
                                                BFA_IOC_FWIMG_MINSZ)
                return;
 
-       /**
+       /*
         * decrement usage count
         */
        bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
-       usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg);
+       usecnt = readl(ioc->ioc_regs.ioc_usage_reg);
        bfa_assert(usecnt > 0);
 
        usecnt--;
-       bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt);
+       writel(usecnt, ioc->ioc_regs.ioc_usage_reg);
        bfa_trc(ioc, usecnt);
 
        bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
 }
 
-/**
+/*
  * Notify other functions on HB failure.
  */
 static void
 bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc)
 {
        if (ioc->cna) {
-               bfa_reg_write(ioc->ioc_regs.ll_halt, __FW_INIT_HALT_P);
+               writel(__FW_INIT_HALT_P, ioc->ioc_regs.ll_halt);
                /* Wait for halt to take effect */
-               bfa_reg_read(ioc->ioc_regs.ll_halt);
+               readl(ioc->ioc_regs.ll_halt);
        } else {
-               bfa_reg_write(ioc->ioc_regs.err_set, __PSS_ERR_STATUS_SET);
-               bfa_reg_read(ioc->ioc_regs.err_set);
+               writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set);
+               readl(ioc->ioc_regs.err_set);
        }
 }
 
-/**
+/*
  * Host to LPU mailbox message addresses
  */
 static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = {
@@ -174,7 +174,7 @@ static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = {
        { HOSTFN3_LPU_MBOX0_8, LPU_HOSTFN3_MBOX0_8, HOST_PAGE_NUM_FN3 }
 };
 
-/**
+/*
  * Host <-> LPU mailbox command/status registers - port 0
  */
 static struct { u32 hfn, lpu; } iocreg_mbcmd_p0[] = {
@@ -184,7 +184,7 @@ static struct { u32 hfn, lpu; } iocreg_mbcmd_p0[] = {
        { HOSTFN3_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN3_MBOX0_CMD_STAT }
 };
 
-/**
+/*
  * Host <-> LPU mailbox command/status registers - port 1
  */
 static struct { u32 hfn, lpu; } iocreg_mbcmd_p1[] = {
@@ -197,7 +197,7 @@ static struct { u32 hfn, lpu; } iocreg_mbcmd_p1[] = {
 static void
 bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc)
 {
-       bfa_os_addr_t   rb;
+       void __iomem *rb;
        int             pcifn = bfa_ioc_pcifn(ioc);
 
        rb = bfa_ioc_bar0(ioc);
@@ -236,7 +236,7 @@ bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc)
        ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG);
        ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT);
 
-       /**
+       /*
         * sram memory access
         */
        ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START);
@@ -248,7 +248,7 @@ bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc)
        ioc->ioc_regs.err_set = (rb + ERR_SET_REG);
 }
 
-/**
+/*
  * Initialize IOC to port mapping.
  */
 
@@ -256,13 +256,13 @@ bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc)
 static void
 bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc)
 {
-       bfa_os_addr_t   rb = ioc->pcidev.pci_bar_kva;
+       void __iomem *rb = ioc->pcidev.pci_bar_kva;
        u32     r32;
 
-       /**
+       /*
         * For catapult, base port id on personality register and IOC type
         */
-       r32 = bfa_reg_read(rb + FNC_PERS_REG);
+       r32 = readl(rb + FNC_PERS_REG);
        r32 >>= FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc));
        ioc->port_id = (r32 & __F0_PORT_MAP_MK) >> __F0_PORT_MAP_SH;
 
@@ -270,22 +270,22 @@ bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc)
        bfa_trc(ioc, ioc->port_id);
 }
 
-/**
+/*
  * Set interrupt mode for a function: INTX or MSIX
  */
 static void
 bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix)
 {
-       bfa_os_addr_t   rb = ioc->pcidev.pci_bar_kva;
+       void __iomem *rb = ioc->pcidev.pci_bar_kva;
        u32     r32, mode;
 
-       r32 = bfa_reg_read(rb + FNC_PERS_REG);
+       r32 = readl(rb + FNC_PERS_REG);
        bfa_trc(ioc, r32);
 
        mode = (r32 >> FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))) &
                __F0_INTX_STATUS;
 
-       /**
+       /*
         * If already in desired mode, do not change anything
         */
        if (!msix && mode)
@@ -300,10 +300,10 @@ bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix)
        r32 |= (mode << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
        bfa_trc(ioc, r32);
 
-       bfa_reg_write(rb + FNC_PERS_REG, r32);
+       writel(r32, rb + FNC_PERS_REG);
 }
 
-/**
+/*
  * Cleanup hw semaphore and usecnt registers
  */
 static void
@@ -312,7 +312,7 @@ bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc)
 
        if (ioc->cna) {
                bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
-               bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, 0);
+               writel(0, ioc->ioc_regs.ioc_usage_reg);
                bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
        }
 
@@ -321,7 +321,7 @@ bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc)
         * before we clear it. If it is not locked, writing 1
         * will lock it instead of clearing it.
         */
-       bfa_reg_read(ioc->ioc_regs.ioc_sem_reg);
+       readl(ioc->ioc_regs.ioc_sem_reg);
        bfa_ioc_hw_sem_release(ioc);
 }
 
@@ -331,17 +331,17 @@ bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc)
  * Check the firmware state to know if pll_init has been completed already
  */
 bfa_boolean_t
-bfa_ioc_ct_pll_init_complete(bfa_os_addr_t rb)
+bfa_ioc_ct_pll_init_complete(void __iomem *rb)
 {
-       if ((bfa_reg_read(rb + BFA_IOC0_STATE_REG) == BFI_IOC_OP) ||
-         (bfa_reg_read(rb + BFA_IOC1_STATE_REG) == BFI_IOC_OP))
+       if ((readl(rb + BFA_IOC0_STATE_REG) == BFI_IOC_OP) ||
+         (readl(rb + BFA_IOC1_STATE_REG) == BFI_IOC_OP))
                return BFA_TRUE;
 
        return BFA_FALSE;
 }
 
 bfa_status_t
-bfa_ioc_ct_pll_init(bfa_os_addr_t rb, bfa_boolean_t fcmode)
+bfa_ioc_ct_pll_init(void __iomem *rb, bfa_boolean_t fcmode)
 {
        u32     pll_sclk, pll_fclk, r32;
 
@@ -354,56 +354,51 @@ bfa_ioc_ct_pll_init(bfa_os_addr_t rb, bfa_boolean_t fcmode)
                __APP_PLL_425_JITLMT0_1(3U) |
                __APP_PLL_425_CNTLMT0_1(1U);
        if (fcmode) {
-               bfa_reg_write((rb + OP_MODE), 0);
-               bfa_reg_write((rb + ETH_MAC_SER_REG),
-                               __APP_EMS_CMLCKSEL |
-                               __APP_EMS_REFCKBUFEN2 |
-                               __APP_EMS_CHANNEL_SEL);
+               writel(0, (rb + OP_MODE));
+               writel(__APP_EMS_CMLCKSEL | __APP_EMS_REFCKBUFEN2 |
+                        __APP_EMS_CHANNEL_SEL, (rb + ETH_MAC_SER_REG));
        } else {
-               bfa_reg_write((rb + OP_MODE), __GLOBAL_FCOE_MODE);
-               bfa_reg_write((rb + ETH_MAC_SER_REG),
-                               __APP_EMS_REFCKBUFEN1);
+               writel(__GLOBAL_FCOE_MODE, (rb + OP_MODE));
+               writel(__APP_EMS_REFCKBUFEN1, (rb + ETH_MAC_SER_REG));
        }
-       bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT);
-       bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT);
-       bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
-       bfa_reg_write(rb + APP_PLL_312_CTL_REG, pll_sclk |
-               __APP_PLL_312_LOGIC_SOFT_RESET);
-       bfa_reg_write(rb + APP_PLL_425_CTL_REG, pll_fclk |
-               __APP_PLL_425_LOGIC_SOFT_RESET);
-       bfa_reg_write(rb + APP_PLL_312_CTL_REG, pll_sclk |
-               __APP_PLL_312_LOGIC_SOFT_RESET | __APP_PLL_312_ENABLE);
-       bfa_reg_write(rb + APP_PLL_425_CTL_REG, pll_fclk |
-               __APP_PLL_425_LOGIC_SOFT_RESET | __APP_PLL_425_ENABLE);
-       bfa_reg_read(rb + HOSTFN0_INT_MSK);
-       bfa_os_udelay(2000);
-       bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
-       bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
-       bfa_reg_write(rb + APP_PLL_312_CTL_REG, pll_sclk |
-               __APP_PLL_312_ENABLE);
-       bfa_reg_write(rb + APP_PLL_425_CTL_REG, pll_fclk |
-               __APP_PLL_425_ENABLE);
+       writel(BFI_IOC_UNINIT, (rb + BFA_IOC0_STATE_REG));
+       writel(BFI_IOC_UNINIT, (rb + BFA_IOC1_STATE_REG));
+       writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
+       writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
+       writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
+       writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS));
+       writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
+       writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
+       writel(pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET,
+                       rb + APP_PLL_312_CTL_REG);
+       writel(pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET,
+                       rb + APP_PLL_425_CTL_REG);
+       writel(pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET | __APP_PLL_312_ENABLE,
+                       rb + APP_PLL_312_CTL_REG);
+       writel(pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET | __APP_PLL_425_ENABLE,
+                       rb + APP_PLL_425_CTL_REG);
+       readl(rb + HOSTFN0_INT_MSK);
+       udelay(2000);
+       writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
+       writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS));
+       writel(pll_sclk | __APP_PLL_312_ENABLE, rb + APP_PLL_312_CTL_REG);
+       writel(pll_fclk | __APP_PLL_425_ENABLE, rb + APP_PLL_425_CTL_REG);
        if (!fcmode) {
-               bfa_reg_write((rb + PMM_1T_RESET_REG_P0), __PMM_1T_RESET_P);
-               bfa_reg_write((rb + PMM_1T_RESET_REG_P1), __PMM_1T_RESET_P);
+               writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P0));
+               writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P1));
        }
-       r32 = bfa_reg_read((rb + PSS_CTL_REG));
+       r32 = readl((rb + PSS_CTL_REG));
        r32 &= ~__PSS_LMEM_RESET;
-       bfa_reg_write((rb + PSS_CTL_REG), r32);
-       bfa_os_udelay(1000);
+       writel(r32, (rb + PSS_CTL_REG));
+       udelay(1000);
        if (!fcmode) {
-               bfa_reg_write((rb + PMM_1T_RESET_REG_P0), 0);
-               bfa_reg_write((rb + PMM_1T_RESET_REG_P1), 0);
+               writel(0, (rb + PMM_1T_RESET_REG_P0));
+               writel(0, (rb + PMM_1T_RESET_REG_P1));
        }
 
-       bfa_reg_write((rb + MBIST_CTL_REG), __EDRAM_BISTR_START);
-       bfa_os_udelay(1000);
-       r32 = bfa_reg_read((rb + MBIST_STAT_REG));
-       bfa_reg_write((rb + MBIST_CTL_REG), 0);
+       writel(__EDRAM_BISTR_START, (rb + MBIST_CTL_REG));
+       udelay(1000);
+       r32 = readl((rb + MBIST_STAT_REG));
+       writel(0, (rb + MBIST_CTL_REG));
        return BFA_STATUS_OK;
 }
index 2cd52733867750e76ae7d52cd65c1dae30e812e1..15407ab39e77759e3cafa96214636b19c2fc22bc 100644 (file)
@@ -15,7 +15,7 @@
  * General Public License for more details.
  */
 
-/**
+/*
  *  bfa_modules.h BFA modules
  */
 
@@ -52,7 +52,7 @@ enum {
 };
 
 
-/**
+/*
  * Macro to define a new BFA module
  */
 #define BFA_MODULE(__mod)                                              \
@@ -80,7 +80,7 @@ enum {
 
 #define BFA_CACHELINE_SZ       (256)
 
-/**
+/*
  * Structure used to interact between different BFA sub modules
  *
  * Each sub module needs to implement only the entry points relevant to it (and
index 788a250ffb8a01b05a6701cab2ecd1e3308016f7..65df62ef437fa349029f05ba76aa774f818ba8cf 100644 (file)
  * General Public License for more details.
  */
 
-/**
- * Contains declarations all OS Specific files needed for BFA layer
- */
-
 #ifndef __BFA_OS_INC_H__
 #define __BFA_OS_INC_H__
 
 #define __BIGENDIAN
 #endif
 
-static inline u64 bfa_os_get_clock(void)
-{
-       return jiffies;
-}
-
 static inline u64 bfa_os_get_log_time(void)
 {
        u64 system_time = 0;
@@ -63,13 +54,6 @@ static inline u64 bfa_os_get_log_time(void)
 #define bfa_io_lat_clock_res_div HZ
 #define bfa_io_lat_clock_res_mul 1000
 
-#define BFA_ASSERT(p) do {                                             \
-       if (!(p)) {      \
-               printk(KERN_ERR "assert(%s) failed at %s:%d\n",         \
-               #p, __FILE__, __LINE__);      \
-       }                                                               \
-} while (0)
-
 #define BFA_LOG(level, bfad, mask, fmt, arg...)                                \
 do {                                                                   \
        if (((mask) == 4) || (level[1] <= '4'))                         \
@@ -81,22 +65,6 @@ do {                                                                 \
        ((_x) & 0x00ff00) |                     \
        (((_x) & 0xff0000) >> 16))
 
-#define bfa_swap_8b(_x)                                        \
-       ((((_x) & 0xff00000000000000ull) >> 56)         \
-        | (((_x) & 0x00ff000000000000ull) >> 40)       \
-        | (((_x) & 0x0000ff0000000000ull) >> 24)       \
-        | (((_x) & 0x000000ff00000000ull) >> 8)        \
-        | (((_x) & 0x00000000ff000000ull) << 8)        \
-        | (((_x) & 0x0000000000ff0000ull) << 24)       \
-        | (((_x) & 0x000000000000ff00ull) << 40)       \
-        | (((_x) & 0x00000000000000ffull) << 56))
-
-#define bfa_os_swap32(_x)                      \
-       ((((_x) & 0xff) << 24)          |       \
-       (((_x) & 0x0000ff00) << 8)      |       \
-       (((_x) & 0x00ff0000) >> 8)      |       \
-       (((_x) & 0xff000000) >> 24))
-
 #define bfa_os_swap_sgaddr(_x)  ((u64)(                                 \
        (((u64)(_x) & (u64)0x00000000000000ffull) << 32)        |       \
        (((u64)(_x) & (u64)0x000000000000ff00ull) << 32)        |       \
@@ -108,59 +76,27 @@ do {                                                                       \
        (((u64)(_x) & (u64)0xff00000000000000ull) >> 32)))
 
 #ifndef __BIGENDIAN
-#define bfa_os_htons(_x) ((u16)((((_x) & 0xff00) >> 8) | \
-                                (((_x) & 0x00ff) << 8)))
-#define bfa_os_htonl(_x)       bfa_os_swap32(_x)
-#define bfa_os_htonll(_x)      bfa_swap_8b(_x)
-#define bfa_os_hton3b(_x)      bfa_swap_3b(_x)
-#define bfa_os_wtole(_x)   (_x)
+#define bfa_os_hton3b(_x)  bfa_swap_3b(_x)
 #define bfa_os_sgaddr(_x)  (_x)
-
 #else
-
-#define bfa_os_htons(_x)   (_x)
-#define bfa_os_htonl(_x)   (_x)
 #define bfa_os_hton3b(_x)  (_x)
-#define bfa_os_htonll(_x)  (_x)
-#define bfa_os_wtole(_x)   bfa_os_swap32(_x)
 #define bfa_os_sgaddr(_x)  bfa_os_swap_sgaddr(_x)
-
 #endif
 
-#define bfa_os_ntohs(_x)   bfa_os_htons(_x)
-#define bfa_os_ntohl(_x)   bfa_os_htonl(_x)
-#define bfa_os_ntohll(_x)  bfa_os_htonll(_x)
 #define bfa_os_ntoh3b(_x)  bfa_os_hton3b(_x)
-
 #define bfa_os_u32(__pa64) ((__pa64) >> 32)
 
-#define bfa_os_memset  memset
-#define bfa_os_memcpy  memcpy
-#define bfa_os_udelay  udelay
-#define bfa_os_vsprintf vsprintf
-#define bfa_os_snprintf snprintf
-
-#define bfa_os_assign(__t, __s) __t = __s
-#define bfa_os_addr_t void __iomem *
-
-#define bfa_os_reg_read(_raddr) readl(_raddr)
-#define bfa_os_reg_write(_raddr, _val) writel((_val), (_raddr))
-#define bfa_os_mem_read(_raddr, _off)                                  \
-       bfa_os_swap32(readl(((_raddr) + (_off))))
-#define bfa_os_mem_write(_raddr, _off, _val)                           \
-       writel(bfa_os_swap32((_val)), ((_raddr) + (_off)))
-
-#define BFA_TRC_TS(_trcm)                                              \
-                       ({                                              \
-                               struct timeval tv;                      \
-                                                                       \
-                               do_gettimeofday(&tv);      \
-                               (tv.tv_sec*1000000+tv.tv_usec);      \
-                        })
+#define BFA_TRC_TS(_trcm)                              \
+       ({                                              \
+               struct timeval tv;                      \
+                                                       \
+               do_gettimeofday(&tv);                   \
+               (tv.tv_sec*1000000+tv.tv_usec);         \
+        })
 
 #define boolean_t int
 
-/**
+/*
  * For current time stamp, OS API will fill-in
  */
 struct bfa_timeval_s {
index b6d170a13bea4f88c8ebbc78d4c63a523b4781b8..fff96226a383c6c06363d9e1036301f88d5bf8ac 100644 (file)
@@ -37,16 +37,16 @@ bfa_port_stats_swap(struct bfa_port_s *port, union bfa_port_stats_u *stats)
                t0 = dip[i];
                t1 = dip[i + 1];
 #ifdef __BIGENDIAN
-               dip[i] = bfa_os_ntohl(t0);
-               dip[i + 1] = bfa_os_ntohl(t1);
+               dip[i] = be32_to_cpu(t0);
+               dip[i + 1] = be32_to_cpu(t1);
 #else
-               dip[i] = bfa_os_ntohl(t1);
-               dip[i + 1] = bfa_os_ntohl(t0);
+               dip[i] = be32_to_cpu(t1);
+               dip[i + 1] = be32_to_cpu(t0);
 #endif
        }
 }
 
-/**
+/*
  * bfa_port_enable_isr()
  *
  *
@@ -63,7 +63,7 @@ bfa_port_enable_isr(struct bfa_port_s *port, bfa_status_t status)
        port->endis_cbfn(port->endis_cbarg, status);
 }
 
-/**
+/*
  * bfa_port_disable_isr()
  *
  *
@@ -80,7 +80,7 @@ bfa_port_disable_isr(struct bfa_port_s *port, bfa_status_t status)
        port->endis_cbfn(port->endis_cbarg, status);
 }
 
-/**
+/*
  * bfa_port_get_stats_isr()
  *
  *
@@ -112,7 +112,7 @@ bfa_port_get_stats_isr(struct bfa_port_s *port, bfa_status_t status)
        }
 }
 
-/**
+/*
  * bfa_port_clear_stats_isr()
  *
  *
@@ -129,7 +129,7 @@ bfa_port_clear_stats_isr(struct bfa_port_s *port, bfa_status_t status)
        port->stats_status = status;
        port->stats_busy   = BFA_FALSE;
 
-       /**
+       /*
        * re-initialize time stamp for stats reset
        */
        bfa_os_gettimeofday(&tv);
@@ -141,7 +141,7 @@ bfa_port_clear_stats_isr(struct bfa_port_s *port, bfa_status_t status)
        }
 }
 
-/**
+/*
  * bfa_port_isr()
  *
  *
@@ -189,7 +189,7 @@ bfa_port_isr(void *cbarg, struct bfi_mbmsg_s *m)
        }
 }
 
-/**
+/*
  * bfa_port_meminfo()
  *
  *
@@ -203,7 +203,7 @@ bfa_port_meminfo(void)
        return BFA_ROUNDUP(sizeof(union bfa_port_stats_u), BFA_DMA_ALIGN_SZ);
 }
 
-/**
+/*
  * bfa_port_mem_claim()
  *
  *
@@ -220,7 +220,7 @@ bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva, u64 dma_pa)
        port->stats_dma.pa  = dma_pa;
 }
 
-/**
+/*
  * bfa_port_enable()
  *
  *   Send the Port enable request to the f/w
@@ -264,7 +264,7 @@ bfa_port_enable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn,
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  * bfa_port_disable()
  *
  *   Send the Port disable request to the f/w
@@ -308,7 +308,7 @@ bfa_port_disable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn,
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  * bfa_port_get_stats()
  *
  *   Send the request to the f/w to fetch Port statistics.
@@ -348,7 +348,7 @@ bfa_port_get_stats(struct bfa_port_s *port, union bfa_port_stats_u *stats,
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  * bfa_port_clear_stats()
  *
  *
@@ -385,7 +385,7 @@ bfa_port_clear_stats(struct bfa_port_s *port, bfa_port_stats_cbfn_t cbfn,
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  * bfa_port_hbfail()
  *
  *
@@ -415,7 +415,7 @@ bfa_port_hbfail(void *arg)
        }
 }
 
-/**
+/*
  * bfa_port_attach()
  *
  *
@@ -449,7 +449,7 @@ bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc,
        bfa_ioc_hbfail_init(&port->hbfail, bfa_port_hbfail, port);
        bfa_ioc_hbfail_register(port->ioc, &port->hbfail);
 
-       /**
+       /*
         * initialize time stamp for stats reset
         */
        bfa_os_gettimeofday(&tv);
@@ -458,7 +458,7 @@ bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc,
        bfa_trc(port, 0);
 }
 
-/**
+/*
  * bfa_port_detach()
  *
  *
index aa1dc749b28195eca325ee97921f91bdeaa95c42..c768143f4805a7cb5f0094682a39c30b73ea433d 100644 (file)
@@ -29,7 +29,7 @@ BFA_MODULE(fcport);
 BFA_MODULE(rport);
 BFA_MODULE(uf);
 
-/**
+/*
  * LPS related definitions
  */
 #define BFA_LPS_MIN_LPORTS      (1)
@@ -41,7 +41,7 @@ BFA_MODULE(uf);
 #define BFA_LPS_MAX_VPORTS_SUPP_CB  255
 #define BFA_LPS_MAX_VPORTS_SUPP_CT  190
 
-/**
+/*
  *  lps_pvt BFA LPS private functions
  */
 
@@ -55,7 +55,7 @@ enum bfa_lps_event {
        BFA_LPS_SM_RX_CVL       = 7,    /* Rx clear virtual link        */
 };
 
-/**
+/*
  * FC PORT related definitions
  */
 /*
@@ -67,7 +67,7 @@ enum bfa_lps_event {
        (bfa_ioc_is_disabled(&bfa->ioc) == BFA_TRUE))
 
 
-/**
+/*
  * BFA port state machine events
  */
 enum bfa_fcport_sm_event {
@@ -82,7 +82,7 @@ enum bfa_fcport_sm_event {
        BFA_FCPORT_SM_HWFAIL    = 9,    /*  IOC h/w failure             */
 };
 
-/**
+/*
  * BFA port link notification state machine events
  */
 
@@ -92,7 +92,7 @@ enum bfa_fcport_ln_sm_event {
        BFA_FCPORT_LN_SM_NOTIFICATION   = 3     /*  done notification   */
 };
 
-/**
+/*
  * RPORT related definitions
  */
 #define bfa_rport_offline_cb(__rp) do {                                        \
@@ -126,7 +126,7 @@ enum bfa_rport_event {
        BFA_RPORT_SM_QRESUME    = 9,    /*  space in requeue queue      */
 };
 
-/**
+/*
  * forward declarations FCXP related functions
  */
 static void    __bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete);
@@ -138,7 +138,7 @@ static void bfa_fcxp_qresume(void *cbarg);
 static void    bfa_fcxp_queue(struct bfa_fcxp_s *fcxp,
                                struct bfi_fcxp_send_req_s *send_req);
 
-/**
+/*
  * forward declarations for LPS functions
  */
 static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len,
@@ -163,7 +163,7 @@ static void bfa_lps_login_comp(struct bfa_lps_s *lps);
 static void bfa_lps_logout_comp(struct bfa_lps_s *lps);
 static void bfa_lps_cvl_event(struct bfa_lps_s *lps);
 
-/**
+/*
  * forward declaration for LPS state machine
  */
 static void bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event);
@@ -175,7 +175,7 @@ static void bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event);
 static void bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event
                                        event);
 
-/**
+/*
  * forward declaration for FC Port functions
  */
 static bfa_boolean_t bfa_fcport_send_enable(struct bfa_fcport_s *fcport);
@@ -193,7 +193,7 @@ static void bfa_fcport_stats_get_timeout(void *cbarg);
 static void bfa_fcport_stats_clr_timeout(void *cbarg);
 static void bfa_trunk_iocdisable(struct bfa_s *bfa);
 
-/**
+/*
  * forward declaration for FC PORT state machine
  */
 static void     bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport,
@@ -252,7 +252,7 @@ static struct bfa_sm_table_s hal_port_sm_table[] = {
 };
 
 
-/**
+/*
  * forward declaration for RPORT related functions
  */
 static struct bfa_rport_s *bfa_rport_alloc(struct bfa_rport_mod_s *rp_mod);
@@ -265,7 +265,7 @@ static void         __bfa_cb_rport_online(void *cbarg,
 static void            __bfa_cb_rport_offline(void *cbarg,
                                                bfa_boolean_t complete);
 
-/**
+/*
  * forward declaration for RPORT state machine
  */
 static void     bfa_rport_sm_uninit(struct bfa_rport_s *rp,
@@ -295,7 +295,7 @@ static void     bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp,
 static void     bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp,
                                        enum bfa_rport_event event);
 
-/**
+/*
  * PLOG related definitions
  */
 static int
@@ -330,7 +330,7 @@ bfa_plog_add(struct bfa_plog_s *plog, struct bfa_plog_rec_s *pl_rec)
 
        pl_recp = &(plog->plog_recs[tail]);
 
-       bfa_os_memcpy(pl_recp, pl_rec, sizeof(struct bfa_plog_rec_s));
+       memcpy(pl_recp, pl_rec, sizeof(struct bfa_plog_rec_s));
 
        pl_recp->tv = bfa_os_get_log_time();
        BFA_PL_LOG_REC_INCR(plog->tail);
@@ -342,9 +342,9 @@ bfa_plog_add(struct bfa_plog_s *plog, struct bfa_plog_rec_s *pl_rec)
 void
 bfa_plog_init(struct bfa_plog_s *plog)
 {
-       bfa_os_memset((char *)plog, 0, sizeof(struct bfa_plog_s));
+       memset((char *)plog, 0, sizeof(struct bfa_plog_s));
 
-       bfa_os_memcpy(plog->plog_sig, BFA_PL_SIG_STR, BFA_PL_SIG_LEN);
+       memcpy(plog->plog_sig, BFA_PL_SIG_STR, BFA_PL_SIG_LEN);
        plog->head = plog->tail = 0;
        plog->plog_enabled = 1;
 }
@@ -357,7 +357,7 @@ bfa_plog_str(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
        struct bfa_plog_rec_s  lp;
 
        if (plog->plog_enabled) {
-               bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
+               memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
                lp.mid = mid;
                lp.eid = event;
                lp.log_type = BFA_PL_LOG_TYPE_STRING;
@@ -381,15 +381,14 @@ bfa_plog_intarr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
                num_ints = BFA_PL_INT_LOG_SZ;
 
        if (plog->plog_enabled) {
-               bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
+               memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
                lp.mid = mid;
                lp.eid = event;
                lp.log_type = BFA_PL_LOG_TYPE_INT;
                lp.misc = misc;
 
                for (i = 0; i < num_ints; i++)
-                       bfa_os_assign(lp.log_entry.int_log[i],
-                                       intarr[i]);
+                       lp.log_entry.int_log[i] = intarr[i];
 
                lp.log_num_ints = (u8) num_ints;
 
@@ -407,7 +406,7 @@ bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
        u32     ints[BFA_PL_INT_LOG_SZ];
 
        if (plog->plog_enabled) {
-               bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
+               memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
 
                ints[0] = tmp_int[0];
                ints[1] = tmp_int[1];
@@ -427,7 +426,7 @@ bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
        u32     ints[BFA_PL_INT_LOG_SZ];
 
        if (plog->plog_enabled) {
-               bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
+               memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
 
                ints[0] = tmp_int[0];
                ints[1] = tmp_int[1];
@@ -462,7 +461,7 @@ bfa_plog_get_setting(struct bfa_plog_s *plog)
        return (bfa_boolean_t)plog->plog_enabled;
 }
 
-/**
+/*
  *  fcxp_pvt BFA FCXP private functions
  */
 
@@ -485,7 +484,7 @@ claim_fcxp_req_rsp_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi)
        mod->req_pld_list_pa = dm_pa;
        dm_kva += buf_pool_sz;
        dm_pa += buf_pool_sz;
-       bfa_os_memset(mod->req_pld_list_kva, 0, buf_pool_sz);
+       memset(mod->req_pld_list_kva, 0, buf_pool_sz);
 
        /*
         * Initialize the fcxp rsp payload list
@@ -495,7 +494,7 @@ claim_fcxp_req_rsp_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi)
        mod->rsp_pld_list_pa = dm_pa;
        dm_kva += buf_pool_sz;
        dm_pa += buf_pool_sz;
-       bfa_os_memset(mod->rsp_pld_list_kva, 0, buf_pool_sz);
+       memset(mod->rsp_pld_list_kva, 0, buf_pool_sz);
 
        bfa_meminfo_dma_virt(mi) = dm_kva;
        bfa_meminfo_dma_phys(mi) = dm_pa;
@@ -508,7 +507,7 @@ claim_fcxps_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi)
        struct bfa_fcxp_s *fcxp;
 
        fcxp = (struct bfa_fcxp_s *) bfa_meminfo_kva(mi);
-       bfa_os_memset(fcxp, 0, sizeof(struct bfa_fcxp_s) * mod->num_fcxps);
+       memset(fcxp, 0, sizeof(struct bfa_fcxp_s) * mod->num_fcxps);
 
        INIT_LIST_HEAD(&mod->fcxp_free_q);
        INIT_LIST_HEAD(&mod->fcxp_active_q);
@@ -559,11 +558,11 @@ bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
 {
        struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
 
-       bfa_os_memset(mod, 0, sizeof(struct bfa_fcxp_mod_s));
+       memset(mod, 0, sizeof(struct bfa_fcxp_mod_s));
        mod->bfa = bfa;
        mod->num_fcxps = cfg->fwcfg.num_fcxp_reqs;
 
-       /**
+       /*
         * Initialize FCXP request and response payload sizes.
         */
        mod->req_pld_sz = mod->rsp_pld_sz = BFA_FCXP_MAX_IBUF_SZ;
@@ -741,20 +740,20 @@ hal_fcxp_send_comp(struct bfa_s *bfa, struct bfi_fcxp_send_rsp_s *fcxp_rsp)
 {
        struct bfa_fcxp_mod_s   *mod = BFA_FCXP_MOD(bfa);
        struct bfa_fcxp_s       *fcxp;
-       u16             fcxp_tag = bfa_os_ntohs(fcxp_rsp->fcxp_tag);
+       u16             fcxp_tag = be16_to_cpu(fcxp_rsp->fcxp_tag);
 
        bfa_trc(bfa, fcxp_tag);
 
-       fcxp_rsp->rsp_len = bfa_os_ntohl(fcxp_rsp->rsp_len);
+       fcxp_rsp->rsp_len = be32_to_cpu(fcxp_rsp->rsp_len);
 
-       /**
+       /*
         * @todo f/w should not set residue to non-0 when everything
         *       is received.
         */
        if (fcxp_rsp->req_status == BFA_STATUS_OK)
                fcxp_rsp->residue_len = 0;
        else
-               fcxp_rsp->residue_len = bfa_os_ntohl(fcxp_rsp->residue_len);
+               fcxp_rsp->residue_len = be32_to_cpu(fcxp_rsp->residue_len);
 
        fcxp = BFA_FCXP_FROM_TAG(mod, fcxp_tag);
 
@@ -856,7 +855,7 @@ hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp,
        }
 }
 
-/**
+/*
  * Handler to resume sending fcxp when space in available in cpe queue.
  */
 static void
@@ -871,7 +870,7 @@ bfa_fcxp_qresume(void *cbarg)
        bfa_fcxp_queue(fcxp, send_req);
 }
 
-/**
+/*
  * Queue fcxp send request to foimrware.
  */
 static void
@@ -885,26 +884,26 @@ bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req)
        bfi_h2i_set(send_req->mh, BFI_MC_FCXP, BFI_FCXP_H2I_SEND_REQ,
                    bfa_lpuid(bfa));
 
-       send_req->fcxp_tag = bfa_os_htons(fcxp->fcxp_tag);
+       send_req->fcxp_tag = cpu_to_be16(fcxp->fcxp_tag);
        if (rport) {
                send_req->rport_fw_hndl = rport->fw_handle;
-               send_req->max_frmsz = bfa_os_htons(rport->rport_info.max_frmsz);
+               send_req->max_frmsz = cpu_to_be16(rport->rport_info.max_frmsz);
                if (send_req->max_frmsz == 0)
-                       send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ);
+                       send_req->max_frmsz = cpu_to_be16(FC_MAX_PDUSZ);
        } else {
                send_req->rport_fw_hndl = 0;
-               send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ);
+               send_req->max_frmsz = cpu_to_be16(FC_MAX_PDUSZ);
        }
 
-       send_req->vf_id = bfa_os_htons(reqi->vf_id);
+       send_req->vf_id = cpu_to_be16(reqi->vf_id);
        send_req->lp_tag = reqi->lp_tag;
        send_req->class = reqi->class;
        send_req->rsp_timeout = rspi->rsp_timeout;
        send_req->cts = reqi->cts;
        send_req->fchs = reqi->fchs;
 
-       send_req->req_len = bfa_os_htonl(reqi->req_tot_len);
-       send_req->rsp_maxlen = bfa_os_htonl(rspi->rsp_maxlen);
+       send_req->req_len = cpu_to_be32(reqi->req_tot_len);
+       send_req->rsp_maxlen = cpu_to_be32(rspi->rsp_maxlen);
 
        /*
         * setup req sgles
@@ -955,11 +954,11 @@ bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req)
        bfa_trc(bfa, bfa_reqq_ci(bfa, BFA_REQQ_FCXP));
 }
 
-/**
+/*
  *  hal_fcxp_api BFA FCXP API
  */
 
-/**
+/*
  * Allocate an FCXP instance to send a response or to send a request
  * that has a response. Request/response buffers are allocated by caller.
  *
@@ -1005,7 +1004,7 @@ bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles,
        return fcxp;
 }
 
-/**
+/*
  * Get the internal request buffer pointer
  *
  * @param[in]  fcxp    BFA fcxp pointer
@@ -1032,7 +1031,7 @@ bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp)
        return mod->req_pld_sz;
 }
 
-/**
+/*
  * Get the internal response buffer pointer
  *
  * @param[in]  fcxp    BFA fcxp pointer
@@ -1052,7 +1051,7 @@ bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp)
        return rspbuf;
 }
 
-/**
+/*
  *             Free the BFA FCXP
  *
  * @param[in]  fcxp                    BFA fcxp pointer
@@ -1069,7 +1068,7 @@ bfa_fcxp_free(struct bfa_fcxp_s *fcxp)
        bfa_fcxp_put(fcxp);
 }
 
-/**
+/*
  * Send a FCXP request
  *
  * @param[in]  fcxp    BFA fcxp pointer
@@ -1103,7 +1102,7 @@ bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport,
 
        bfa_trc(bfa, fcxp->fcxp_tag);
 
-       /**
+       /*
         * setup request/response info
         */
        reqi->bfa_rport = rport;
@@ -1118,7 +1117,7 @@ bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport,
        fcxp->send_cbfn = cbfn ? cbfn : bfa_fcxp_null_comp;
        fcxp->send_cbarg = cbarg;
 
-       /**
+       /*
         * If no room in CPE queue, wait for space in request queue
         */
        send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP);
@@ -1132,7 +1131,7 @@ bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport,
        bfa_fcxp_queue(fcxp, send_req);
 }
 
-/**
+/*
  * Abort a BFA FCXP
  *
  * @param[in]  fcxp    BFA fcxp pointer
@@ -1186,7 +1185,7 @@ bfa_fcxp_walloc_cancel(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe)
 void
 bfa_fcxp_discard(struct bfa_fcxp_s *fcxp)
 {
-       /**
+       /*
         * If waiting for room in request queue, cancel reqq wait
         * and free fcxp.
         */
@@ -1202,7 +1201,7 @@ bfa_fcxp_discard(struct bfa_fcxp_s *fcxp)
 
 
 
-/**
+/*
  *  hal_fcxp_public BFA FCXP public functions
  */
 
@@ -1229,11 +1228,11 @@ bfa_fcxp_get_maxrsp(struct bfa_s *bfa)
 }
 
 
-/**
+/*
  *  BFA LPS state machine functions
  */
 
-/**
+/*
  * Init state -- no login
  */
 static void
@@ -1285,7 +1284,7 @@ bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event)
        }
 }
 
-/**
+/*
  * login is in progress -- awaiting response from firmware
  */
 static void
@@ -1327,7 +1326,7 @@ bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event)
        }
 }
 
-/**
+/*
  * login pending - awaiting space in request queue
  */
 static void
@@ -1359,7 +1358,7 @@ bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event)
        }
 }
 
-/**
+/*
  * login complete
  */
 static void
@@ -1400,7 +1399,7 @@ bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event)
        }
 }
 
-/**
+/*
  * logout in progress - awaiting firmware response
  */
 static void
@@ -1424,7 +1423,7 @@ bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event)
        }
 }
 
-/**
+/*
  * logout pending -- awaiting space in request queue
  */
 static void
@@ -1451,11 +1450,11 @@ bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event)
 
 
 
-/**
+/*
  *  lps_pvt BFA LPS private functions
  */
 
-/**
+/*
  * return memory requirement
  */
 static void
@@ -1468,7 +1467,7 @@ bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len,
                *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MAX_LPORTS;
 }
 
-/**
+/*
  * bfa module attach at initialization time
  */
 static void
@@ -1479,7 +1478,7 @@ bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
        struct bfa_lps_s        *lps;
        int                     i;
 
-       bfa_os_memset(mod, 0, sizeof(struct bfa_lps_mod_s));
+       memset(mod, 0, sizeof(struct bfa_lps_mod_s));
        mod->num_lps = BFA_LPS_MAX_LPORTS;
        if (cfg->drvcfg.min_cfg)
                mod->num_lps = BFA_LPS_MIN_LPORTS;
@@ -1516,7 +1515,7 @@ bfa_lps_stop(struct bfa_s *bfa)
 {
 }
 
-/**
+/*
  * IOC in disabled state -- consider all lps offline
  */
 static void
@@ -1532,7 +1531,7 @@ bfa_lps_iocdisable(struct bfa_s *bfa)
        }
 }
 
-/**
+/*
  * Firmware login response
  */
 static void
@@ -1550,7 +1549,7 @@ bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp)
                lps->fport      = rsp->f_port;
                lps->npiv_en    = rsp->npiv_en;
                lps->lp_pid     = rsp->lp_pid;
-               lps->pr_bbcred  = bfa_os_ntohs(rsp->bb_credit);
+               lps->pr_bbcred  = be16_to_cpu(rsp->bb_credit);
                lps->pr_pwwn    = rsp->port_name;
                lps->pr_nwwn    = rsp->node_name;
                lps->auth_req   = rsp->auth_req;
@@ -1579,7 +1578,7 @@ bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp)
        bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP);
 }
 
-/**
+/*
  * Firmware logout response
  */
 static void
@@ -1594,7 +1593,7 @@ bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp)
        bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP);
 }
 
-/**
+/*
  * Firmware received a Clear virtual link request (for FCoE)
  */
 static void
@@ -1608,7 +1607,7 @@ bfa_lps_rx_cvl_event(struct bfa_s *bfa, struct bfi_lps_cvl_event_s *cvl)
        bfa_sm_send_event(lps, BFA_LPS_SM_RX_CVL);
 }
 
-/**
+/*
  * Space is available in request queue, resume queueing request to firmware.
  */
 static void
@@ -1619,7 +1618,7 @@ bfa_lps_reqq_resume(void *lps_arg)
        bfa_sm_send_event(lps, BFA_LPS_SM_RESUME);
 }
 
-/**
+/*
  * lps is freed -- triggered by vport delete
  */
 static void
@@ -1632,7 +1631,7 @@ bfa_lps_free(struct bfa_lps_s *lps)
        list_add_tail(&lps->qe, &mod->lps_free_q);
 }
 
-/**
+/*
  * send login request to firmware
  */
 static void
@@ -1648,7 +1647,7 @@ bfa_lps_send_login(struct bfa_lps_s *lps)
 
        m->lp_tag       = lps->lp_tag;
        m->alpa         = lps->alpa;
-       m->pdu_size     = bfa_os_htons(lps->pdusz);
+       m->pdu_size     = cpu_to_be16(lps->pdusz);
        m->pwwn         = lps->pwwn;
        m->nwwn         = lps->nwwn;
        m->fdisc        = lps->fdisc;
@@ -1657,7 +1656,7 @@ bfa_lps_send_login(struct bfa_lps_s *lps)
        bfa_reqq_produce(lps->bfa, lps->reqq);
 }
 
-/**
+/*
  * send logout request to firmware
  */
 static void
@@ -1676,7 +1675,7 @@ bfa_lps_send_logout(struct bfa_lps_s *lps)
        bfa_reqq_produce(lps->bfa, lps->reqq);
 }
 
-/**
+/*
  * Indirect login completion handler for non-fcs
  */
 static void
@@ -1693,7 +1692,7 @@ bfa_lps_login_comp_cb(void *arg, bfa_boolean_t complete)
                bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status);
 }
 
-/**
+/*
  * Login completion handler -- direct call for fcs, queue for others
  */
 static void
@@ -1711,7 +1710,7 @@ bfa_lps_login_comp(struct bfa_lps_s *lps)
                bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status);
 }
 
-/**
+/*
  * Indirect logout completion handler for non-fcs
  */
 static void
@@ -1726,7 +1725,7 @@ bfa_lps_logout_comp_cb(void *arg, bfa_boolean_t complete)
                bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg);
 }
 
-/**
+/*
  * Logout completion handler -- direct call for fcs, queue for others
  */
 static void
@@ -1741,7 +1740,7 @@ bfa_lps_logout_comp(struct bfa_lps_s *lps)
                bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg);
 }
 
-/**
+/*
  * Clear virtual link completion handler for non-fcs
  */
 static void
@@ -1757,7 +1756,7 @@ bfa_lps_cvl_event_cb(void *arg, bfa_boolean_t complete)
                bfa_cb_lps_cvl_event(lps->bfa->bfad, lps->uarg);
 }
 
-/**
+/*
  * Received Clear virtual link event --direct call for fcs,
  * queue for others
  */
@@ -1777,7 +1776,7 @@ bfa_lps_cvl_event(struct bfa_lps_s *lps)
 
 
 
-/**
+/*
  *  lps_public BFA LPS public functions
  */
 
@@ -1790,7 +1789,7 @@ bfa_lps_get_max_vport(struct bfa_s *bfa)
                return BFA_LPS_MAX_VPORTS_SUPP_CB;
 }
 
-/**
+/*
  * Allocate a lport srvice tag.
  */
 struct bfa_lps_s  *
@@ -1810,7 +1809,7 @@ bfa_lps_alloc(struct bfa_s *bfa)
        return lps;
 }
 
-/**
+/*
  * Free lport service tag. This can be called anytime after an alloc.
  * No need to wait for any pending login/logout completions.
  */
@@ -1820,7 +1819,7 @@ bfa_lps_delete(struct bfa_lps_s *lps)
        bfa_sm_send_event(lps, BFA_LPS_SM_DELETE);
 }
 
-/**
+/*
  * Initiate a lport login.
  */
 void
@@ -1837,7 +1836,7 @@ bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz,
        bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN);
 }
 
-/**
+/*
  * Initiate a lport fdisc login.
  */
 void
@@ -1854,7 +1853,7 @@ bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn,
        bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN);
 }
 
-/**
+/*
  * Initiate a lport logout (flogi).
  */
 void
@@ -1863,7 +1862,7 @@ bfa_lps_flogo(struct bfa_lps_s *lps)
        bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT);
 }
 
-/**
+/*
  * Initiate a lport FDSIC logout.
  */
 void
@@ -1872,7 +1871,7 @@ bfa_lps_fdisclogo(struct bfa_lps_s *lps)
        bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT);
 }
 
-/**
+/*
  * Discard a pending login request -- should be called only for
  * link down handling.
  */
@@ -1882,7 +1881,7 @@ bfa_lps_discard(struct bfa_lps_s *lps)
        bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE);
 }
 
-/**
+/*
  * Return lport services tag
  */
 u8
@@ -1891,7 +1890,7 @@ bfa_lps_get_tag(struct bfa_lps_s *lps)
        return lps->lp_tag;
 }
 
-/**
+/*
  * Return lport services tag given the pid
  */
 u8
@@ -1910,7 +1909,7 @@ bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid)
        return 0;
 }
 
-/**
+/*
  * return if fabric login indicates support for NPIV
  */
 bfa_boolean_t
@@ -1919,7 +1918,7 @@ bfa_lps_is_npiv_en(struct bfa_lps_s *lps)
        return lps->npiv_en;
 }
 
-/**
+/*
  * Return TRUE if attached to F-Port, else return FALSE
  */
 bfa_boolean_t
@@ -1928,7 +1927,7 @@ bfa_lps_is_fport(struct bfa_lps_s *lps)
        return lps->fport;
 }
 
-/**
+/*
  * Return TRUE if attached to a Brocade Fabric
  */
 bfa_boolean_t
@@ -1936,7 +1935,7 @@ bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps)
 {
        return lps->brcd_switch;
 }
-/**
+/*
  * return TRUE if authentication is required
  */
 bfa_boolean_t
@@ -1951,7 +1950,7 @@ bfa_lps_get_extstatus(struct bfa_lps_s *lps)
        return lps->ext_status;
 }
 
-/**
+/*
  * return port id assigned to the lport
  */
 u32
@@ -1960,7 +1959,7 @@ bfa_lps_get_pid(struct bfa_lps_s *lps)
        return lps->lp_pid;
 }
 
-/**
+/*
  * return port id assigned to the base lport
  */
 u32
@@ -1971,7 +1970,7 @@ bfa_lps_get_base_pid(struct bfa_s *bfa)
        return BFA_LPS_FROM_TAG(mod, 0)->lp_pid;
 }
 
-/**
+/*
  * Return bb_credit assigned in FLOGI response
  */
 u16
@@ -1980,7 +1979,7 @@ bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps)
        return lps->pr_bbcred;
 }
 
-/**
+/*
  * Return peer port name
  */
 wwn_t
@@ -1989,7 +1988,7 @@ bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps)
        return lps->pr_pwwn;
 }
 
-/**
+/*
  * Return peer node name
  */
 wwn_t
@@ -1998,7 +1997,7 @@ bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps)
        return lps->pr_nwwn;
 }
 
-/**
+/*
  * return reason code if login request is rejected
  */
 u8
@@ -2007,7 +2006,7 @@ bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps)
        return lps->lsrjt_rsn;
 }
 
-/**
+/*
  * return explanation code if login request is rejected
  */
 u8
@@ -2016,7 +2015,7 @@ bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps)
        return lps->lsrjt_expl;
 }
 
-/**
+/*
  * Return fpma/spma MAC for lport
  */
 mac_t
@@ -2025,7 +2024,7 @@ bfa_lps_get_lp_mac(struct bfa_lps_s *lps)
        return lps->lp_mac;
 }
 
-/**
+/*
  * LPS firmware message class handler.
  */
 void
@@ -2055,7 +2054,7 @@ bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
        }
 }
 
-/**
+/*
  * FC PORT state machine functions
  */
 static void
@@ -2066,7 +2065,7 @@ bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport,
 
        switch (event) {
        case BFA_FCPORT_SM_START:
-               /**
+               /*
                 * Start event after IOC is configured and BFA is started.
                 */
                if (bfa_fcport_send_enable(fcport)) {
@@ -2080,7 +2079,7 @@ bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport,
                break;
 
        case BFA_FCPORT_SM_ENABLE:
-               /**
+               /*
                 * Port is persistently configured to be in enabled state. Do
                 * not change state. Port enabling is done when START event is
                 * received.
@@ -2088,7 +2087,7 @@ bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport,
                break;
 
        case BFA_FCPORT_SM_DISABLE:
-               /**
+               /*
                 * If a port is persistently configured to be disabled, the
                 * first event will a port disable request.
                 */
@@ -2124,13 +2123,13 @@ bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport,
                break;
 
        case BFA_FCPORT_SM_ENABLE:
-               /**
+               /*
                 * Already enable is in progress.
                 */
                break;
 
        case BFA_FCPORT_SM_DISABLE:
-               /**
+               /*
                 * Just send disable request to firmware when room becomes
                 * available in request queue.
                 */
@@ -2145,7 +2144,7 @@ bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport,
 
        case BFA_FCPORT_SM_LINKUP:
        case BFA_FCPORT_SM_LINKDOWN:
-               /**
+               /*
                 * Possible to get link events when doing back-to-back
                 * enable/disables.
                 */
@@ -2184,7 +2183,7 @@ bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport,
                break;
 
        case BFA_FCPORT_SM_ENABLE:
-               /**
+               /*
                 * Already being enabled.
                 */
                break;
@@ -2257,13 +2256,13 @@ bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport,
                break;
 
        case BFA_FCPORT_SM_LINKDOWN:
-               /**
+               /*
                 * Possible to get link down event.
                 */
                break;
 
        case BFA_FCPORT_SM_ENABLE:
-               /**
+               /*
                 * Already enabled.
                 */
                break;
@@ -2306,7 +2305,7 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport,
 
        switch (event) {
        case BFA_FCPORT_SM_ENABLE:
-               /**
+               /*
                 * Already enabled.
                 */
                break;
@@ -2399,14 +2398,14 @@ bfa_fcport_sm_disabling_qwait(struct bfa_fcport_s *fcport,
                break;
 
        case BFA_FCPORT_SM_DISABLE:
-               /**
+               /*
                 * Already being disabled.
                 */
                break;
 
        case BFA_FCPORT_SM_LINKUP:
        case BFA_FCPORT_SM_LINKDOWN:
-               /**
+               /*
                 * Possible to get link events when doing back-to-back
                 * enable/disables.
                 */
@@ -2453,7 +2452,7 @@ bfa_fcport_sm_toggling_qwait(struct bfa_fcport_s *fcport,
 
        case BFA_FCPORT_SM_LINKUP:
        case BFA_FCPORT_SM_LINKDOWN:
-               /**
+               /*
                 * Possible to get link events when doing back-to-back
                 * enable/disables.
                 */
@@ -2483,7 +2482,7 @@ bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport,
                break;
 
        case BFA_FCPORT_SM_DISABLE:
-               /**
+               /*
                 * Already being disabled.
                 */
                break;
@@ -2508,7 +2507,7 @@ bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport,
 
        case BFA_FCPORT_SM_LINKUP:
        case BFA_FCPORT_SM_LINKDOWN:
-               /**
+               /*
                 * Possible to get link events when doing back-to-back
                 * enable/disables.
                 */
@@ -2533,7 +2532,7 @@ bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport,
 
        switch (event) {
        case BFA_FCPORT_SM_START:
-               /**
+               /*
                 * Ignore start event for a port that is disabled.
                 */
                break;
@@ -2557,7 +2556,7 @@ bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport,
                break;
 
        case BFA_FCPORT_SM_DISABLE:
-               /**
+               /*
                 * Already disabled.
                 */
                break;
@@ -2587,14 +2586,14 @@ bfa_fcport_sm_stopped(struct bfa_fcport_s *fcport,
                break;
 
        default:
-               /**
+               /*
                 * Ignore all other events.
                 */
                ;
        }
 }
 
-/**
+/*
  * Port is enabled. IOC is down/failed.
  */
 static void
@@ -2613,14 +2612,14 @@ bfa_fcport_sm_iocdown(struct bfa_fcport_s *fcport,
                break;
 
        default:
-               /**
+               /*
                 * Ignore all events.
                 */
                ;
        }
 }
 
-/**
+/*
  * Port is disabled. IOC is down/failed.
  */
 static void
@@ -2639,14 +2638,14 @@ bfa_fcport_sm_iocfail(struct bfa_fcport_s *fcport,
                break;
 
        default:
-               /**
+               /*
                 * Ignore all events.
                 */
                ;
        }
 }
 
-/**
+/*
  * Link state is down
  */
 static void
@@ -2666,7 +2665,7 @@ bfa_fcport_ln_sm_dn(struct bfa_fcport_ln_s *ln,
        }
 }
 
-/**
+/*
  * Link state is waiting for down notification
  */
 static void
@@ -2689,7 +2688,7 @@ bfa_fcport_ln_sm_dn_nf(struct bfa_fcport_ln_s *ln,
        }
 }
 
-/**
+/*
  * Link state is waiting for down notification and there is a pending up
  */
 static void
@@ -2713,7 +2712,7 @@ bfa_fcport_ln_sm_dn_up_nf(struct bfa_fcport_ln_s *ln,
        }
 }
 
-/**
+/*
  * Link state is up
  */
 static void
@@ -2733,7 +2732,7 @@ bfa_fcport_ln_sm_up(struct bfa_fcport_ln_s *ln,
        }
 }
 
-/**
+/*
  * Link state is waiting for up notification
  */
 static void
@@ -2756,7 +2755,7 @@ bfa_fcport_ln_sm_up_nf(struct bfa_fcport_ln_s *ln,
        }
 }
 
-/**
+/*
  * Link state is waiting for up notification and there is a pending down
  */
 static void
@@ -2780,7 +2779,7 @@ bfa_fcport_ln_sm_up_dn_nf(struct bfa_fcport_ln_s *ln,
        }
 }
 
-/**
+/*
  * Link state is waiting for up notification and there are pending down and up
  */
 static void
@@ -2806,7 +2805,7 @@ bfa_fcport_ln_sm_up_dn_up_nf(struct bfa_fcport_ln_s *ln,
 
 
 
-/**
+/*
  *  hal_port_private
  */
 
@@ -2821,7 +2820,7 @@ __bfa_cb_fcport_event(void *cbarg, bfa_boolean_t complete)
                bfa_sm_send_event(ln, BFA_FCPORT_LN_SM_NOTIFICATION);
 }
 
-/**
+/*
  * Send SCN notification to upper layers.
  * trunk - false if caller is fcport to ignore fcport event in trunked mode
  */
@@ -2897,7 +2896,7 @@ bfa_fcport_mem_claim(struct bfa_fcport_s *fcport, struct bfa_meminfo_s *meminfo)
        bfa_meminfo_dma_phys(meminfo) = dm_pa;
 }
 
-/**
+/*
  * Memory initialization.
  */
 static void
@@ -2909,7 +2908,7 @@ bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
        struct bfa_fcport_ln_s *ln = &fcport->ln;
        struct bfa_timeval_s tv;
 
-       bfa_os_memset(fcport, 0, sizeof(struct bfa_fcport_s));
+       memset(fcport, 0, sizeof(struct bfa_fcport_s));
        fcport->bfa = bfa;
        ln->fcport = fcport;
 
@@ -2918,13 +2917,13 @@ bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
        bfa_sm_set_state(fcport, bfa_fcport_sm_uninit);
        bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn);
 
-       /**
+       /*
         * initialize time stamp for stats reset
         */
        bfa_os_gettimeofday(&tv);
        fcport->stats_reset_time = tv.tv_sec;
 
-       /**
+       /*
         * initialize and set default configuration
         */
        port_cfg->topology = BFA_PORT_TOPOLOGY_P2P;
@@ -2942,7 +2941,7 @@ bfa_fcport_detach(struct bfa_s *bfa)
 {
 }
 
-/**
+/*
  * Called when IOC is ready.
  */
 static void
@@ -2951,7 +2950,7 @@ bfa_fcport_start(struct bfa_s *bfa)
        bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_START);
 }
 
-/**
+/*
  * Called before IOC is stopped.
  */
 static void
@@ -2961,7 +2960,7 @@ bfa_fcport_stop(struct bfa_s *bfa)
        bfa_trunk_iocdisable(bfa);
 }
 
-/**
+/*
  * Called when IOC failure is detected.
  */
 static void
@@ -2986,18 +2985,17 @@ bfa_fcport_update_linkinfo(struct bfa_fcport_s *fcport)
                fcport->myalpa = 0;
 
        /* QoS Details */
-       bfa_os_assign(fcport->qos_attr, pevent->link_state.qos_attr);
-       bfa_os_assign(fcport->qos_vc_attr,
-               pevent->link_state.vc_fcf.qos_vc_attr);
+       fcport->qos_attr = pevent->link_state.qos_attr;
+       fcport->qos_vc_attr = pevent->link_state.vc_fcf.qos_vc_attr;
 
-       /**
+       /*
         * update trunk state if applicable
         */
        if (!fcport->cfg.trunked)
                trunk->attr.state = BFA_TRUNK_DISABLED;
 
        /* update FCoE specific */
-       fcport->fcoe_vlan = bfa_os_ntohs(pevent->link_state.vc_fcf.fcf.vlan);
+       fcport->fcoe_vlan = be16_to_cpu(pevent->link_state.vc_fcf.fcf.vlan);
 
        bfa_trc(fcport->bfa, fcport->speed);
        bfa_trc(fcport->bfa, fcport->topology);
@@ -3010,7 +3008,7 @@ bfa_fcport_reset_linkinfo(struct bfa_fcport_s *fcport)
        fcport->topology = BFA_PORT_TOPOLOGY_NONE;
 }
 
-/**
+/*
  * Send port enable message to firmware.
  */
 static bfa_boolean_t
@@ -3018,13 +3016,13 @@ bfa_fcport_send_enable(struct bfa_fcport_s *fcport)
 {
        struct bfi_fcport_enable_req_s *m;
 
-       /**
+       /*
         * Increment message tag before queue check, so that responses to old
         * requests are discarded.
         */
        fcport->msgtag++;
 
-       /**
+       /*
         * check for room in queue to send request now
         */
        m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT);
@@ -3040,19 +3038,19 @@ bfa_fcport_send_enable(struct bfa_fcport_s *fcport)
        m->pwwn = fcport->pwwn;
        m->port_cfg = fcport->cfg;
        m->msgtag = fcport->msgtag;
-       m->port_cfg.maxfrsize = bfa_os_htons(fcport->cfg.maxfrsize);
+       m->port_cfg.maxfrsize = cpu_to_be16(fcport->cfg.maxfrsize);
        bfa_dma_be_addr_set(m->stats_dma_addr, fcport->stats_pa);
        bfa_trc(fcport->bfa, m->stats_dma_addr.a32.addr_lo);
        bfa_trc(fcport->bfa, m->stats_dma_addr.a32.addr_hi);
 
-       /**
+       /*
         * queue I/O message to firmware
         */
        bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT);
        return BFA_TRUE;
 }
 
-/**
+/*
  * Send port disable message to firmware.
  */
 static bfa_boolean_t
@@ -3060,13 +3058,13 @@ bfa_fcport_send_disable(struct bfa_fcport_s *fcport)
 {
        struct bfi_fcport_req_s *m;
 
-       /**
+       /*
         * Increment message tag before queue check, so that responses to old
         * requests are discarded.
         */
        fcport->msgtag++;
 
-       /**
+       /*
         * check for room in queue to send request now
         */
        m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT);
@@ -3080,7 +3078,7 @@ bfa_fcport_send_disable(struct bfa_fcport_s *fcport)
                        bfa_lpuid(fcport->bfa));
        m->msgtag = fcport->msgtag;
 
-       /**
+       /*
         * queue I/O message to firmware
         */
        bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT);
@@ -3105,7 +3103,7 @@ bfa_fcport_send_txcredit(void *port_cbarg)
        struct bfa_fcport_s *fcport = port_cbarg;
        struct bfi_fcport_set_svc_params_req_s *m;
 
-       /**
+       /*
         * check for room in queue to send request now
         */
        m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT);
@@ -3116,9 +3114,9 @@ bfa_fcport_send_txcredit(void *port_cbarg)
 
        bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ,
                        bfa_lpuid(fcport->bfa));
-       m->tx_bbcredit = bfa_os_htons((u16)fcport->cfg.tx_bbcredit);
+       m->tx_bbcredit = cpu_to_be16((u16)fcport->cfg.tx_bbcredit);
 
-       /**
+       /*
         * queue I/O message to firmware
         */
        bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT);
@@ -3134,7 +3132,7 @@ bfa_fcport_qos_stats_swap(struct bfa_qos_stats_s *d,
 
        /* Now swap the 32 bit fields */
        for (i = 0; i < (sizeof(struct bfa_qos_stats_s)/sizeof(u32)); ++i)
-               dip[i] = bfa_os_ntohl(sip[i]);
+               dip[i] = be32_to_cpu(sip[i]);
 }
 
 static void
@@ -3148,11 +3146,11 @@ bfa_fcport_fcoe_stats_swap(struct bfa_fcoe_stats_s *d,
        for (i = 0; i < ((sizeof(struct bfa_fcoe_stats_s))/sizeof(u32));
             i = i + 2) {
 #ifdef __BIGENDIAN
-               dip[i] = bfa_os_ntohl(sip[i]);
-               dip[i + 1] = bfa_os_ntohl(sip[i + 1]);
+               dip[i] = be32_to_cpu(sip[i]);
+               dip[i + 1] = be32_to_cpu(sip[i + 1]);
 #else
-               dip[i] = bfa_os_ntohl(sip[i + 1]);
-               dip[i + 1] = bfa_os_ntohl(sip[i]);
+               dip[i] = be32_to_cpu(sip[i + 1]);
+               dip[i + 1] = be32_to_cpu(sip[i]);
 #endif
        }
 }
@@ -3223,7 +3221,7 @@ bfa_fcport_send_stats_get(void *cbarg)
        }
        fcport->stats_qfull = BFA_FALSE;
 
-       bfa_os_memset(msg, 0, sizeof(struct bfi_fcport_req_s));
+       memset(msg, 0, sizeof(struct bfi_fcport_req_s));
        bfi_h2i_set(msg->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_STATS_GET_REQ,
                        bfa_lpuid(fcport->bfa));
        bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT);
@@ -3237,7 +3235,7 @@ __bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete)
        if (complete) {
                struct bfa_timeval_s tv;
 
-               /**
+               /*
                 * re-initialize time stamp for stats reset
                 */
                bfa_os_gettimeofday(&tv);
@@ -3285,13 +3283,13 @@ bfa_fcport_send_stats_clear(void *cbarg)
        }
        fcport->stats_qfull = BFA_FALSE;
 
-       bfa_os_memset(msg, 0, sizeof(struct bfi_fcport_req_s));
+       memset(msg, 0, sizeof(struct bfi_fcport_req_s));
        bfi_h2i_set(msg->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_STATS_CLEAR_REQ,
                        bfa_lpuid(fcport->bfa));
        bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT);
 }
 
-/**
+/*
  * Handle trunk SCN event from firmware.
  */
 static void
@@ -3312,7 +3310,7 @@ bfa_trunk_scn(struct bfa_fcport_s *fcport, struct bfi_fcport_trunk_scn_s *scn)
        bfa_trc(fcport->bfa, scn->trunk_state);
        bfa_trc(fcport->bfa, scn->trunk_speed);
 
-       /**
+       /*
         * Save off new state for trunk attribute query
         */
        state_prev = trunk->attr.state;
@@ -3327,7 +3325,7 @@ bfa_trunk_scn(struct bfa_fcport_s *fcport, struct bfi_fcport_trunk_scn_s *scn)
                lattr->trunk_wwn  = tlink->trunk_wwn;
                lattr->fctl       = tlink->fctl;
                lattr->speed      = tlink->speed;
-               lattr->deskew     = bfa_os_ntohl(tlink->deskew);
+               lattr->deskew     = be32_to_cpu(tlink->deskew);
 
                if (tlink->state == BFA_TRUNK_LINK_STATE_UP) {
                        fcport->speed    = tlink->speed;
@@ -3360,7 +3358,7 @@ bfa_trunk_scn(struct bfa_fcport_s *fcport, struct bfi_fcport_trunk_scn_s *scn)
                        BFA_PL_EID_TRUNK_SCN, 0, "Trunk down");
        }
 
-       /**
+       /*
         * Notify upper layers if trunk state changed.
         */
        if ((state_prev != trunk->attr.state) ||
@@ -3376,7 +3374,7 @@ bfa_trunk_iocdisable(struct bfa_s *bfa)
        struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
        int i = 0;
 
-       /**
+       /*
         * In trunked mode, notify upper layers that link is down
         */
        if (fcport->cfg.trunked) {
@@ -3400,11 +3398,11 @@ bfa_trunk_iocdisable(struct bfa_s *bfa)
 
 
 
-/**
+/*
  *  hal_port_public
  */
 
-/**
+/*
  * Called to initialize port attributes
  */
 void
@@ -3412,7 +3410,7 @@ bfa_fcport_init(struct bfa_s *bfa)
 {
        struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       /**
+       /*
         * Initialize port attributes from IOC hardware data.
         */
        bfa_fcport_set_wwns(fcport);
@@ -3426,7 +3424,7 @@ bfa_fcport_init(struct bfa_s *bfa)
        bfa_assert(fcport->speed_sup);
 }
 
-/**
+/*
  * Firmware message handler.
  */
 void
@@ -3507,11 +3505,11 @@ bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
 
 
 
-/**
+/*
  *  hal_port_api
  */
 
-/**
+/*
  * Registered callback for port events.
  */
 void
@@ -3552,7 +3550,7 @@ bfa_fcport_disable(struct bfa_s *bfa)
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  * Configure port speed.
  */
 bfa_status_t
@@ -3574,7 +3572,7 @@ bfa_fcport_cfg_speed(struct bfa_s *bfa, enum bfa_port_speed speed)
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  * Get current speed.
  */
 enum bfa_port_speed
@@ -3585,7 +3583,7 @@ bfa_fcport_get_speed(struct bfa_s *bfa)
        return fcport->speed;
 }
 
-/**
+/*
  * Configure port topology.
  */
 bfa_status_t
@@ -3610,7 +3608,7 @@ bfa_fcport_cfg_topology(struct bfa_s *bfa, enum bfa_port_topology topology)
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  * Get current topology.
  */
 enum bfa_port_topology
@@ -3710,7 +3708,7 @@ bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit)
        bfa_fcport_send_txcredit(fcport);
 }
 
-/**
+/*
  * Get port attributes.
  */
 
@@ -3729,7 +3727,7 @@ bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr)
 {
        struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       bfa_os_memset(attr, 0, sizeof(struct bfa_port_attr_s));
+       memset(attr, 0, sizeof(struct bfa_port_attr_s));
 
        attr->nwwn = fcport->nwwn;
        attr->pwwn = fcport->pwwn;
@@ -3737,7 +3735,7 @@ bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr)
        attr->factorypwwn =  bfa_ioc_get_mfg_pwwn(&bfa->ioc);
        attr->factorynwwn =  bfa_ioc_get_mfg_nwwn(&bfa->ioc);
 
-       bfa_os_memcpy(&attr->pport_cfg, &fcport->cfg,
+       memcpy(&attr->pport_cfg, &fcport->cfg,
                sizeof(struct bfa_port_cfg_s));
        /* speed attributes */
        attr->pport_cfg.speed = fcport->cfg.speed;
@@ -3770,7 +3768,7 @@ bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr)
 
 #define BFA_FCPORT_STATS_TOV   1000
 
-/**
+/*
  * Fetch port statistics (FCQoS or FCoE).
  */
 bfa_status_t
@@ -3796,7 +3794,7 @@ bfa_fcport_get_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  * Reset port statistics (FCQoS or FCoE).
  */
 bfa_status_t
@@ -3820,7 +3818,7 @@ bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, void *cbarg)
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  * Fetch FCQoS port statistics
  */
 bfa_status_t
@@ -3833,7 +3831,7 @@ bfa_fcport_get_qos_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
        return bfa_fcport_get_stats(bfa, stats, cbfn, cbarg);
 }
 
-/**
+/*
  * Reset FCoE port statistics
  */
 bfa_status_t
@@ -3845,7 +3843,7 @@ bfa_fcport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, void *cbarg)
        return bfa_fcport_clear_stats(bfa, cbfn, cbarg);
 }
 
-/**
+/*
  * Fetch FCQoS port statistics
  */
 bfa_status_t
@@ -3858,7 +3856,7 @@ bfa_fcport_get_fcoe_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
        return bfa_fcport_get_stats(bfa, stats, cbfn, cbarg);
 }
 
-/**
+/*
  * Reset FCoE port statistics
  */
 bfa_status_t
@@ -3876,7 +3874,7 @@ bfa_fcport_qos_get_attr(struct bfa_s *bfa, struct bfa_qos_attr_s *qos_attr)
        struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
        qos_attr->state = fcport->qos_attr.state;
-       qos_attr->total_bb_cr = bfa_os_ntohl(fcport->qos_attr.total_bb_cr);
+       qos_attr->total_bb_cr = be32_to_cpu(fcport->qos_attr.total_bb_cr);
 }
 
 void
@@ -3887,10 +3885,10 @@ bfa_fcport_qos_get_vc_attr(struct bfa_s *bfa,
        struct bfa_qos_vc_attr_s *bfa_vc_attr = &fcport->qos_vc_attr;
        u32 i = 0;
 
-       qos_vc_attr->total_vc_count = bfa_os_ntohs(bfa_vc_attr->total_vc_count);
-       qos_vc_attr->shared_credit  = bfa_os_ntohs(bfa_vc_attr->shared_credit);
+       qos_vc_attr->total_vc_count = be16_to_cpu(bfa_vc_attr->total_vc_count);
+       qos_vc_attr->shared_credit  = be16_to_cpu(bfa_vc_attr->shared_credit);
        qos_vc_attr->elp_opmode_flags  =
-                       bfa_os_ntohl(bfa_vc_attr->elp_opmode_flags);
+                       be32_to_cpu(bfa_vc_attr->elp_opmode_flags);
 
        /* Individual VC info */
        while (i < qos_vc_attr->total_vc_count) {
@@ -3904,7 +3902,7 @@ bfa_fcport_qos_get_vc_attr(struct bfa_s *bfa,
        }
 }
 
-/**
+/*
  * Fetch port attributes.
  */
 bfa_boolean_t
@@ -3939,7 +3937,7 @@ bfa_fcport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off)
 
        if (ioc_type == BFA_IOC_TYPE_FC) {
                fcport->cfg.qos_enabled = on_off;
-               /**
+               /*
                 * Notify fcpim of the change in QoS state
                 */
                bfa_fcpim_update_ioredirect(bfa);
@@ -3959,7 +3957,7 @@ bfa_fcport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off)
                fcport->cfg.trl_def_speed = BFA_PORT_SPEED_1GBPS;
 }
 
-/**
+/*
  * Configure default minimum ratelim speed
  */
 bfa_status_t
@@ -3980,7 +3978,7 @@ bfa_fcport_cfg_ratelim_speed(struct bfa_s *bfa, enum bfa_port_speed speed)
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  * Get default minimum ratelim speed
  */
 enum bfa_port_speed
@@ -4095,10 +4093,10 @@ bfa_trunk_disable(struct bfa_s *bfa)
 }
 
 
-/**
+/*
  * Rport State machine functions
  */
-/**
+/*
  * Beginning state, only online event expected.
  */
 static void
@@ -4151,7 +4149,7 @@ bfa_rport_sm_created(struct bfa_rport_s *rp, enum bfa_rport_event event)
        }
 }
 
-/**
+/*
  * Waiting for rport create response from firmware.
  */
 static void
@@ -4188,7 +4186,7 @@ bfa_rport_sm_fwcreate(struct bfa_rport_s *rp, enum bfa_rport_event event)
        }
 }
 
-/**
+/*
  * Request queue is full, awaiting queue resume to send create request.
  */
 static void
@@ -4229,7 +4227,7 @@ bfa_rport_sm_fwcreate_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event)
        }
 }
 
-/**
+/*
  * Online state - normal parking state.
  */
 static void
@@ -4275,9 +4273,9 @@ bfa_rport_sm_online(struct bfa_rport_s *rp, enum bfa_rport_event event)
                bfa_trc(rp->bfa, qos_scn->new_qos_attr.qos_priority);
 
                qos_scn->old_qos_attr.qos_flow_id  =
-                       bfa_os_ntohl(qos_scn->old_qos_attr.qos_flow_id);
+                       be32_to_cpu(qos_scn->old_qos_attr.qos_flow_id);
                qos_scn->new_qos_attr.qos_flow_id  =
-                       bfa_os_ntohl(qos_scn->new_qos_attr.qos_flow_id);
+                       be32_to_cpu(qos_scn->new_qos_attr.qos_flow_id);
 
                if (qos_scn->old_qos_attr.qos_flow_id !=
                        qos_scn->new_qos_attr.qos_flow_id)
@@ -4297,7 +4295,7 @@ bfa_rport_sm_online(struct bfa_rport_s *rp, enum bfa_rport_event event)
        }
 }
 
-/**
+/*
  * Firmware rport is being deleted - awaiting f/w response.
  */
 static void
@@ -4360,7 +4358,7 @@ bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event)
        }
 }
 
-/**
+/*
  * Offline state.
  */
 static void
@@ -4395,7 +4393,7 @@ bfa_rport_sm_offline(struct bfa_rport_s *rp, enum bfa_rport_event event)
        }
 }
 
-/**
+/*
  * Rport is deleted, waiting for firmware response to delete.
  */
 static void
@@ -4447,7 +4445,7 @@ bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event)
        }
 }
 
-/**
+/*
  * Waiting for rport create response from firmware. A delete is pending.
  */
 static void
@@ -4478,7 +4476,7 @@ bfa_rport_sm_delete_pending(struct bfa_rport_s *rp,
        }
 }
 
-/**
+/*
  * Waiting for rport create response from firmware. Rport offline is pending.
  */
 static void
@@ -4513,7 +4511,7 @@ bfa_rport_sm_offline_pending(struct bfa_rport_s *rp,
        }
 }
 
-/**
+/*
  * IOC h/w failed.
  */
 static void
@@ -4553,7 +4551,7 @@ bfa_rport_sm_iocdisable(struct bfa_rport_s *rp, enum bfa_rport_event event)
 
 
 
-/**
+/*
  *  bfa_rport_private BFA rport private functions
  */
 
@@ -4612,12 +4610,12 @@ bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
                   !(mod->num_rports & (mod->num_rports - 1)));
 
        for (i = 0; i < mod->num_rports; i++, rp++) {
-               bfa_os_memset(rp, 0, sizeof(struct bfa_rport_s));
+               memset(rp, 0, sizeof(struct bfa_rport_s));
                rp->bfa = bfa;
                rp->rport_tag = i;
                bfa_sm_set_state(rp, bfa_rport_sm_uninit);
 
-               /**
+               /*
                 *  - is unused
                 */
                if (i)
@@ -4626,7 +4624,7 @@ bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
                bfa_reqq_winit(&rp->reqq_wait, bfa_rport_qresume, rp);
        }
 
-       /**
+       /*
         * consume memory
         */
        bfa_meminfo_kva(meminfo) = (u8 *) rp;
@@ -4687,7 +4685,7 @@ bfa_rport_send_fwcreate(struct bfa_rport_s *rp)
 {
        struct bfi_rport_create_req_s *m;
 
-       /**
+       /*
         * check for room in queue to send request now
         */
        m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT);
@@ -4699,7 +4697,7 @@ bfa_rport_send_fwcreate(struct bfa_rport_s *rp)
        bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_CREATE_REQ,
                        bfa_lpuid(rp->bfa));
        m->bfa_handle = rp->rport_tag;
-       m->max_frmsz = bfa_os_htons(rp->rport_info.max_frmsz);
+       m->max_frmsz = cpu_to_be16(rp->rport_info.max_frmsz);
        m->pid = rp->rport_info.pid;
        m->lp_tag = rp->rport_info.lp_tag;
        m->local_pid = rp->rport_info.local_pid;
@@ -4708,7 +4706,7 @@ bfa_rport_send_fwcreate(struct bfa_rport_s *rp)
        m->vf_id = rp->rport_info.vf_id;
        m->cisc = rp->rport_info.cisc;
 
-       /**
+       /*
         * queue I/O message to firmware
         */
        bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT);
@@ -4720,7 +4718,7 @@ bfa_rport_send_fwdelete(struct bfa_rport_s *rp)
 {
        struct bfi_rport_delete_req_s *m;
 
-       /**
+       /*
         * check for room in queue to send request now
         */
        m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT);
@@ -4733,7 +4731,7 @@ bfa_rport_send_fwdelete(struct bfa_rport_s *rp)
                        bfa_lpuid(rp->bfa));
        m->fw_handle = rp->fw_handle;
 
-       /**
+       /*
         * queue I/O message to firmware
         */
        bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT);
@@ -4745,7 +4743,7 @@ bfa_rport_send_fwspeed(struct bfa_rport_s *rp)
 {
        struct bfa_rport_speed_req_s *m;
 
-       /**
+       /*
         * check for room in queue to send request now
         */
        m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT);
@@ -4759,7 +4757,7 @@ bfa_rport_send_fwspeed(struct bfa_rport_s *rp)
        m->fw_handle = rp->fw_handle;
        m->speed = (u8)rp->rport_info.speed;
 
-       /**
+       /*
         * queue I/O message to firmware
         */
        bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT);
@@ -4768,11 +4766,11 @@ bfa_rport_send_fwspeed(struct bfa_rport_s *rp)
 
 
 
-/**
+/*
  *  bfa_rport_public
  */
 
-/**
+/*
  * Rport interrupt processing.
  */
 void
@@ -4814,7 +4812,7 @@ bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
 
 
 
-/**
+/*
  *  bfa_rport_api
  */
 
@@ -4849,7 +4847,7 @@ bfa_rport_online(struct bfa_rport_s *rport, struct bfa_rport_info_s *rport_info)
 {
        bfa_assert(rport_info->max_frmsz != 0);
 
-       /**
+       /*
         * Some JBODs are seen to be not setting PDU size correctly in PLOGI
         * responses. Default to minimum size.
         */
@@ -4858,7 +4856,7 @@ bfa_rport_online(struct bfa_rport_s *rport, struct bfa_rport_info_s *rport_info)
                rport_info->max_frmsz = FC_MIN_PDUSZ;
        }
 
-       bfa_os_assign(rport->rport_info, *rport_info);
+       rport->rport_info = *rport_info;
        bfa_sm_send_event(rport, BFA_RPORT_SM_ONLINE);
 }
 
@@ -4890,22 +4888,22 @@ bfa_rport_get_qos_attr(struct bfa_rport_s *rport,
                                        struct bfa_rport_qos_attr_s *qos_attr)
 {
        qos_attr->qos_priority  = rport->qos_attr.qos_priority;
-       qos_attr->qos_flow_id  = bfa_os_ntohl(rport->qos_attr.qos_flow_id);
+       qos_attr->qos_flow_id  = be32_to_cpu(rport->qos_attr.qos_flow_id);
 
 }
 
 void
 bfa_rport_clear_stats(struct bfa_rport_s *rport)
 {
-       bfa_os_memset(&rport->stats, 0, sizeof(rport->stats));
+       memset(&rport->stats, 0, sizeof(rport->stats));
 }
 
 
-/**
+/*
  * SGPG related functions
  */
 
-/**
+/*
  * Compute and return memory needed by FCP(im) module.
  */
 static void
@@ -4957,8 +4955,8 @@ bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
        bfa_assert(!(sgpg_pa.pa & (sizeof(struct bfi_sgpg_s) - 1)));
 
        for (i = 0; i < mod->num_sgpgs; i++) {
-               bfa_os_memset(hsgpg, 0, sizeof(*hsgpg));
-               bfa_os_memset(sgpg, 0, sizeof(*sgpg));
+               memset(hsgpg, 0, sizeof(*hsgpg));
+               memset(sgpg, 0, sizeof(*sgpg));
 
                hsgpg->sgpg = sgpg;
                sgpg_pa_tmp.pa = bfa_sgaddr_le(sgpg_pa.pa);
@@ -4997,7 +4995,7 @@ bfa_sgpg_iocdisable(struct bfa_s *bfa)
 
 
 
-/**
+/*
  *  hal_sgpg_public BFA SGPG public functions
  */
 
@@ -5039,7 +5037,7 @@ bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpg)
        if (list_empty(&mod->sgpg_wait_q))
                return;
 
-       /**
+       /*
         * satisfy as many waiting requests as possible
         */
        do {
@@ -5067,11 +5065,11 @@ bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, int nsgpg)
 
        wqe->nsgpg_total = wqe->nsgpg = nsgpg;
 
-       /**
+       /*
         * allocate any left to this one first
         */
        if (mod->free_sgpgs) {
-               /**
+               /*
                 * no one else is waiting for SGPG
                 */
                bfa_assert(list_empty(&mod->sgpg_wait_q));
@@ -5105,7 +5103,7 @@ bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe, void (*cbfn) (void *cbarg),
        wqe->cbarg = cbarg;
 }
 
-/**
+/*
  *  UF related functions
  */
 /*
@@ -5136,7 +5134,7 @@ claim_uf_pbs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
        bfa_meminfo_dma_virt(mi) += uf_pb_tot_sz;
        bfa_meminfo_dma_phys(mi) += uf_pb_tot_sz;
 
-       bfa_os_memset((void *)ufm->uf_pbs_kva, 0, uf_pb_tot_sz);
+       memset((void *)ufm->uf_pbs_kva, 0, uf_pb_tot_sz);
 }
 
 static void
@@ -5153,11 +5151,11 @@ claim_uf_post_msgs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
 
        for (i = 0, uf_bp_msg = ufm->uf_buf_posts; i < ufm->num_ufs;
             i++, uf_bp_msg++) {
-               bfa_os_memset(uf_bp_msg, 0, sizeof(struct bfi_uf_buf_post_s));
+               memset(uf_bp_msg, 0, sizeof(struct bfi_uf_buf_post_s));
 
                uf_bp_msg->buf_tag = i;
                buf_len = sizeof(struct bfa_uf_buf_s);
-               uf_bp_msg->buf_len = bfa_os_htons(buf_len);
+               uf_bp_msg->buf_len = cpu_to_be16(buf_len);
                bfi_h2i_set(uf_bp_msg->mh, BFI_MC_UF, BFI_UF_H2I_BUF_POST,
                            bfa_lpuid(ufm->bfa));
 
@@ -5173,7 +5171,7 @@ claim_uf_post_msgs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
                bfa_sge_to_be(&sge[1]);
        }
 
-       /**
+       /*
         * advance pointer beyond consumed memory
         */
        bfa_meminfo_kva(mi) = (u8 *) uf_bp_msg;
@@ -5194,7 +5192,7 @@ claim_ufs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
         * Initialize UFs and queue it in UF free queue
         */
        for (i = 0, uf = ufm->uf_list; i < ufm->num_ufs; i++, uf++) {
-               bfa_os_memset(uf, 0, sizeof(struct bfa_uf_s));
+               memset(uf, 0, sizeof(struct bfa_uf_s));
                uf->bfa = ufm->bfa;
                uf->uf_tag = i;
                uf->pb_len = sizeof(struct bfa_uf_buf_s);
@@ -5203,7 +5201,7 @@ claim_ufs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
                list_add_tail(&uf->qe, &ufm->uf_free_q);
        }
 
-       /**
+       /*
         * advance memory pointer
         */
        bfa_meminfo_kva(mi) = (u8 *) uf;
@@ -5241,7 +5239,7 @@ bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
 {
        struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa);
 
-       bfa_os_memset(ufm, 0, sizeof(struct bfa_uf_mod_s));
+       memset(ufm, 0, sizeof(struct bfa_uf_mod_s));
        ufm->bfa = bfa;
        ufm->num_ufs = cfg->fwcfg.num_uf_bufs;
        INIT_LIST_HEAD(&ufm->uf_free_q);
@@ -5279,7 +5277,7 @@ bfa_uf_post(struct bfa_uf_mod_s *ufm, struct bfa_uf_s *uf)
        if (!uf_post_msg)
                return BFA_STATUS_FAILED;
 
-       bfa_os_memcpy(uf_post_msg, &ufm->uf_buf_posts[uf->uf_tag],
+       memcpy(uf_post_msg, &ufm->uf_buf_posts[uf->uf_tag],
                      sizeof(struct bfi_uf_buf_post_s));
        bfa_reqq_produce(ufm->bfa, BFA_REQQ_FCXP);
 
@@ -5310,8 +5308,8 @@ uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m)
        u8 *buf = &uf_buf->d[0];
        struct fchs_s *fchs;
 
-       m->frm_len = bfa_os_ntohs(m->frm_len);
-       m->xfr_len = bfa_os_ntohs(m->xfr_len);
+       m->frm_len = be16_to_cpu(m->frm_len);
+       m->xfr_len = be16_to_cpu(m->xfr_len);
 
        fchs = (struct fchs_s *)uf_buf;
 
@@ -5365,11 +5363,11 @@ bfa_uf_start(struct bfa_s *bfa)
 
 
 
-/**
+/*
  *  hal_uf_api
  */
 
-/**
+/*
  * Register handler for all unsolicted recieve frames.
  *
  * @param[in]  bfa             BFA instance
@@ -5385,7 +5383,7 @@ bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv, void *cbarg)
        ufm->cbarg = cbarg;
 }
 
-/**
+/*
  *     Free an unsolicited frame back to BFA.
  *
  * @param[in]          uf              unsolicited frame to be freed
@@ -5401,7 +5399,7 @@ bfa_uf_free(struct bfa_uf_s *uf)
 
 
 
-/**
+/*
  *  uf_pub BFA uf module public functions
  */
 void
index 9921dad0d0392e4dc58df172871e0fd73c9fa39c..e2349d5cdb931124132e2c6a2b3cc52200dcf40b 100644 (file)
 #include "bfi_ms.h"
 
 
-/**
+/*
  * Scatter-gather DMA related defines
  */
 #define BFA_SGPG_MIN   (16)
 
-/**
+/*
  * Alignment macro for SG page allocation
  */
 #define BFA_SGPG_ROUNDUP(_l) (((_l) + (sizeof(struct bfi_sgpg_s) - 1)) \
@@ -48,7 +48,7 @@ struct bfa_sgpg_s {
        union bfi_addr_u sgpg_pa;       /*  pa of SG page               */
 };
 
-/**
+/*
  * Given number of SG elements, BFA_SGPG_NPAGE() returns the number of
  * SG pages required.
  */
@@ -75,7 +75,7 @@ void bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, int nsgpgs);
 void bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe);
 
 
-/**
+/*
  * FCXP related defines
  */
 #define BFA_FCXP_MIN           (1)
@@ -115,12 +115,12 @@ typedef void (*bfa_fcxp_alloc_cbfn_t) (void *cbarg, struct bfa_fcxp_s *fcxp);
 
 
 
-/**
+/*
  * Information needed for a FCXP request
  */
 struct bfa_fcxp_req_info_s {
        struct bfa_rport_s *bfa_rport;
-                                       /** Pointer to the bfa rport that was
+                                       /* Pointer to the bfa rport that was
                                         * returned from bfa_rport_create().
                                         * This could be left NULL for WKA or
                                         * for FCXP interactions before the
@@ -137,11 +137,10 @@ struct bfa_fcxp_req_info_s {
 
 struct bfa_fcxp_rsp_info_s {
        struct fchs_s   rsp_fchs;
-                               /** !< Response frame's FC header will
+                               /* Response frame's FC header will
                                 * be sent back in this field */
        u8              rsp_timeout;
-                               /** !< timeout in seconds, 0-no response
-                                */
+                               /* timeout in seconds, 0-no response */
        u8              rsvd2[3];
        u32     rsp_maxlen;     /*  max response length expected */
 };
@@ -218,7 +217,7 @@ struct bfa_fcxp_wqe_s {
 void   bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
 
 
-/**
+/*
  * RPORT related defines
  */
 #define BFA_RPORT_MIN  4
@@ -232,7 +231,7 @@ struct bfa_rport_mod_s {
 
 #define BFA_RPORT_MOD(__bfa)   (&(__bfa)->modules.rport_mod)
 
-/**
+/*
  * Convert rport tag to RPORT
  */
 #define BFA_RPORT_FROM_TAG(__bfa, _tag)                                \
@@ -244,7 +243,7 @@ struct bfa_rport_mod_s {
  */
 void   bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
 
-/**
+/*
  *     BFA rport information.
  */
 struct bfa_rport_info_s {
@@ -259,7 +258,7 @@ struct bfa_rport_info_s {
        enum bfa_port_speed speed;      /*  Rport's current speed           */
 };
 
-/**
+/*
  * BFA rport data structure
  */
 struct bfa_rport_s {
@@ -282,7 +281,7 @@ struct bfa_rport_s {
 #define BFA_RPORT_FC_COS(_rport)       ((_rport)->rport_info.fc_class)
 
 
-/**
+/*
  * UF - unsolicited receive related defines
  */
 
@@ -305,7 +304,7 @@ struct bfa_uf_s {
        struct bfa_sge_s sges[BFI_SGE_INLINE_MAX];
 };
 
-/**
+/*
  *      Callback prototype for unsolicited frame receive handler.
  *
  * @param[in]           cbarg           callback arg for receive handler
@@ -338,7 +337,7 @@ void        bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
 
 #define BFA_UF_BUFSZ   (2 * 1024 + 256)
 
-/**
+/*
  * @todo private
  */
 struct bfa_uf_buf_s {
@@ -346,7 +345,7 @@ struct bfa_uf_buf_s {
 };
 
 
-/**
+/*
  * LPS - bfa lport login/logout service interface
  */
 struct bfa_lps_s {
@@ -397,14 +396,14 @@ struct bfa_lps_mod_s {
 void   bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
 
 
-/**
+/*
  * FCPORT related defines
  */
 
 #define BFA_FCPORT(_bfa)       (&((_bfa)->modules.port))
 typedef void (*bfa_cb_port_t) (void *cbarg, enum bfa_status status);
 
-/**
+/*
  * Link notification data structure
  */
 struct bfa_fcport_ln_s {
@@ -418,7 +417,7 @@ struct bfa_fcport_trunk_s {
        struct bfa_trunk_attr_s attr;
 };
 
-/**
+/*
  * BFA FC port data structure
  */
 struct bfa_fcport_s {
@@ -613,7 +612,7 @@ void bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv,
                          void *cbarg);
 void bfa_uf_free(struct bfa_uf_s *uf);
 
-/**
+/*
  * bfa lport service api
  */
 
index 4d8784e06e142a8d0dd4d178cd947dbca6c17ff9..1f938974b84876978600b40d97c265ddd7c2c7c0 100644 (file)
@@ -15,7 +15,7 @@
  * General Public License for more details.
  */
 
-/**
+/*
  *  bfad.c Linux driver PCI interface module.
  */
 #include <linux/module.h>
@@ -151,7 +151,7 @@ bfad_sm_failed(struct bfad_s *bfad, enum bfad_sm_event event);
 static void
 bfad_sm_fcs_exit(struct bfad_s *bfad, enum bfad_sm_event event);
 
-/**
+/*
  * Beginning state for the driver instance, awaiting the pci_probe event
  */
 static void
@@ -181,7 +181,7 @@ bfad_sm_uninit(struct bfad_s *bfad, enum bfad_sm_event event)
        }
 }
 
-/**
+/*
  * Driver Instance is created, awaiting event INIT to initialize the bfad
  */
 static void
@@ -364,7 +364,7 @@ bfad_sm_stopping(struct bfad_s *bfad, enum bfad_sm_event event)
        }
 }
 
-/**
+/*
  *  BFA callbacks
  */
 void
@@ -376,7 +376,7 @@ bfad_hcb_comp(void *arg, bfa_status_t status)
        complete(&fcomp->comp);
 }
 
-/**
+/*
  * bfa_init callback
  */
 void
@@ -401,7 +401,7 @@ bfa_cb_init(void *drv, bfa_status_t init_status)
        complete(&bfad->comp);
 }
 
-/**
+/*
  *  BFA_FCS callbacks
  */
 struct bfad_port_s *
@@ -457,7 +457,7 @@ bfa_fcb_lport_delete(struct bfad_s *bfad, enum bfa_lport_role roles,
        }
 }
 
-/**
+/*
  * FCS RPORT alloc callback, after successful PLOGI by FCS
  */
 bfa_status_t
@@ -478,7 +478,7 @@ ext:
        return rc;
 }
 
-/**
+/*
  * FCS PBC VPORT Create
  */
 void
@@ -663,7 +663,7 @@ ext:
        return rc;
 }
 
-/**
+/*
  * Create a vport under a vf.
  */
 bfa_status_t
@@ -716,30 +716,6 @@ ext:
        return rc;
 }
 
-/**
- * Create a vf and its base vport implicitely.
- */
-bfa_status_t
-bfad_vf_create(struct bfad_s *bfad, u16 vf_id,
-              struct bfa_lport_cfg_s *port_cfg)
-{
-       struct bfad_vf_s      *vf;
-       int             rc = BFA_STATUS_OK;
-
-       vf = kzalloc(sizeof(struct bfad_vf_s), GFP_KERNEL);
-       if (!vf) {
-               rc = BFA_STATUS_FAILED;
-               goto ext;
-       }
-
-       rc = bfa_fcs_vf_create(&vf->fcs_vf, &bfad->bfa_fcs, vf_id, port_cfg,
-                              vf);
-       if (rc != BFA_STATUS_OK)
-               kfree(vf);
-ext:
-       return rc;
-}
-
 void
 bfad_bfa_tmo(unsigned long data)
 {
@@ -885,20 +861,6 @@ bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad)
        pci_set_drvdata(pdev, NULL);
 }
 
-void
-bfad_fcs_port_cfg(struct bfad_s *bfad)
-{
-       struct bfa_lport_cfg_s  port_cfg;
-       struct bfa_port_attr_s attr;
-       char            symname[BFA_SYMNAME_MAXLEN];
-
-       sprintf(symname, "%s-%d", BFAD_DRIVER_NAME, bfad->inst_no);
-       memcpy(port_cfg.sym_name.symname, symname, strlen(symname));
-       bfa_fcport_get_attr(&bfad->bfa, &attr);
-       port_cfg.nwwn = attr.nwwn;
-       port_cfg.pwwn = attr.pwwn;
-}
-
 bfa_status_t
 bfad_drv_init(struct bfad_s *bfad)
 {
@@ -1089,9 +1051,6 @@ bfad_start_ops(struct bfad_s *bfad) {
        bfa_fcs_init(&bfad->bfa_fcs);
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 
-       /* PPORT FCS config */
-       bfad_fcs_port_cfg(bfad);
-
        retval = bfad_cfg_pport(bfad, BFA_LPORT_ROLE_FCP_IM);
        if (retval != BFA_STATUS_OK) {
                if (bfa_sm_cmp_state(bfad, bfad_sm_initializing))
@@ -1181,7 +1140,7 @@ bfad_worker(void *ptr)
        return 0;
 }
 
-/**
+/*
  *  BFA driver interrupt functions
  */
 irqreturn_t
@@ -1240,7 +1199,7 @@ bfad_msix(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/**
+/*
  * Initialize the MSIX entry table.
  */
 static void
@@ -1293,7 +1252,7 @@ bfad_install_msix_handler(struct bfad_s *bfad)
        return 0;
 }
 
-/**
+/*
  * Setup MSIX based interrupt.
  */
 int
@@ -1374,7 +1333,7 @@ bfad_remove_intr(struct bfad_s *bfad)
        }
 }
 
-/**
+/*
  * PCI probe entry.
  */
 int
@@ -1460,7 +1419,7 @@ out:
        return error;
 }
 
-/**
+/*
  * PCI remove entry.
  */
 void
@@ -1541,7 +1500,7 @@ static struct pci_driver bfad_pci_driver = {
        .remove = __devexit_p(bfad_pci_remove),
 };
 
-/**
+/*
  * Driver module init.
  */
 static int __init
@@ -1581,7 +1540,7 @@ ext:
        return error;
 }
 
-/**
+/*
  * Driver module exit.
  */
 static void __exit
index d8843720eac1b42b39606c6af93f1cde39653b5c..ed9fff440b5c3ef00014502120f7f475072b764e 100644 (file)
  * General Public License for more details.
  */
 
-/**
+/*
  *  bfa_attr.c Linux driver configuration interface module.
  */
 
 #include "bfad_drv.h"
 #include "bfad_im.h"
 
-/**
+/*
  * FC transport template entry, get SCSI target port ID.
  */
 void
@@ -48,7 +48,7 @@ bfad_im_get_starget_port_id(struct scsi_target *starget)
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 }
 
-/**
+/*
  * FC transport template entry, get SCSI target nwwn.
  */
 void
@@ -70,11 +70,11 @@ bfad_im_get_starget_node_name(struct scsi_target *starget)
        if (itnim)
                node_name = bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim);
 
-       fc_starget_node_name(starget) = bfa_os_htonll(node_name);
+       fc_starget_node_name(starget) = cpu_to_be64(node_name);
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 }
 
-/**
+/*
  * FC transport template entry, get SCSI target pwwn.
  */
 void
@@ -96,11 +96,11 @@ bfad_im_get_starget_port_name(struct scsi_target *starget)
        if (itnim)
                port_name = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim);
 
-       fc_starget_port_name(starget) = bfa_os_htonll(port_name);
+       fc_starget_port_name(starget) = cpu_to_be64(port_name);
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 }
 
-/**
+/*
  * FC transport template entry, get SCSI host port ID.
  */
 void
@@ -114,7 +114,7 @@ bfad_im_get_host_port_id(struct Scsi_Host *shost)
                        bfa_os_hton3b(bfa_fcs_lport_get_fcid(port->fcs_port));
 }
 
-/**
+/*
  * FC transport template entry, get SCSI host port type.
  */
 static void
@@ -146,7 +146,7 @@ bfad_im_get_host_port_type(struct Scsi_Host *shost)
        }
 }
 
-/**
+/*
  * FC transport template entry, get SCSI host port state.
  */
 static void
@@ -183,7 +183,7 @@ bfad_im_get_host_port_state(struct Scsi_Host *shost)
        }
 }
 
-/**
+/*
  * FC transport template entry, get SCSI host active fc4s.
  */
 static void
@@ -202,7 +202,7 @@ bfad_im_get_host_active_fc4s(struct Scsi_Host *shost)
        fc_host_active_fc4s(shost)[7] = 1;
 }
 
-/**
+/*
  * FC transport template entry, get SCSI host link speed.
  */
 static void
@@ -236,7 +236,7 @@ bfad_im_get_host_speed(struct Scsi_Host *shost)
        }
 }
 
-/**
+/*
  * FC transport template entry, get SCSI host port type.
  */
 static void
@@ -249,11 +249,11 @@ bfad_im_get_host_fabric_name(struct Scsi_Host *shost)
 
        fabric_nwwn = bfa_fcs_lport_get_fabric_name(port->fcs_port);
 
-       fc_host_fabric_name(shost) = bfa_os_htonll(fabric_nwwn);
+       fc_host_fabric_name(shost) = cpu_to_be64(fabric_nwwn);
 
 }
 
-/**
+/*
  * FC transport template entry, get BFAD statistics.
  */
 static struct fc_host_statistics *
@@ -304,7 +304,7 @@ bfad_im_get_stats(struct Scsi_Host *shost)
        return hstats;
 }
 
-/**
+/*
  * FC transport template entry, reset BFAD statistics.
  */
 static void
@@ -331,7 +331,7 @@ bfad_im_reset_stats(struct Scsi_Host *shost)
        return;
 }
 
-/**
+/*
  * FC transport template entry, get rport loss timeout.
  */
 static void
@@ -347,7 +347,7 @@ bfad_im_get_rport_loss_tmo(struct fc_rport *rport)
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 }
 
-/**
+/*
  * FC transport template entry, set rport loss timeout.
  */
 static void
@@ -633,7 +633,7 @@ struct fc_function_template bfad_im_vport_fc_function_template = {
        .set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo,
 };
 
-/**
+/*
  *  Scsi_Host_attrs SCSI host attributes
  */
 static ssize_t
@@ -733,7 +733,7 @@ bfad_im_node_name_show(struct device *dev, struct device_attribute *attr,
        u64        nwwn;
 
        nwwn = bfa_fcs_lport_get_nwwn(port->fcs_port);
-       return snprintf(buf, PAGE_SIZE, "0x%llx\n", bfa_os_htonll(nwwn));
+       return snprintf(buf, PAGE_SIZE, "0x%llx\n", cpu_to_be64(nwwn));
 }
 
 static ssize_t
index 69ed1c4a903eac810fc40a70d86b20e7f440f6c1..1fedeeb4ac1f87dd69e4945c6c3b65fdd4cdab37 100644 (file)
@@ -318,7 +318,7 @@ bfad_debugfs_write_regrd(struct file *file, const char __user *buf,
        regbuf =  (u32 *)bfad->regdata;
        spin_lock_irqsave(&bfad->bfad_lock, flags);
        for (i = 0; i < len; i++) {
-               *regbuf = bfa_reg_read(reg_addr);
+               *regbuf = readl(reg_addr);
                regbuf++;
                reg_addr += sizeof(u32);
        }
@@ -361,7 +361,7 @@ bfad_debugfs_write_regwr(struct file *file, const char __user *buf,
 
        reg_addr = (u32 *) ((u8 *) bfa_ioc_bar0(ioc) + addr);
        spin_lock_irqsave(&bfad->bfad_lock, flags);
-       bfa_reg_write(reg_addr, val);
+       writel(val, reg_addr);
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 
        return nbytes;
index 98420bbb4f3f1d01f6c9035472d42f69a258ab88..97f9b6c0937e75cf3a16762092ac46ac6f6cb890 100644 (file)
  * General Public License for more details.
  */
 
-/**
+/*
  * Contains base driver definitions.
  */
 
-/**
+/*
  *  bfa_drv.h Linux driver data structures.
  */
 
@@ -309,7 +309,6 @@ void                bfad_bfa_tmo(unsigned long data);
 void           bfad_init_timer(struct bfad_s *bfad);
 int            bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad);
 void           bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad);
-void           bfad_fcs_port_cfg(struct bfad_s *bfad);
 void           bfad_drv_uninit(struct bfad_s *bfad);
 int            bfad_worker(void *ptr);
 void           bfad_debugfs_init(struct bfad_port_s *port);
index d950ee44016eeefcf3e8870483f9322f667551ce..8daa716739d1bd6d2a6a4180c008161e7f148f27 100644 (file)
@@ -15,7 +15,7 @@
  * General Public License for more details.
  */
 
-/**
+/*
  *  bfad_im.c Linux driver IM module.
  */
 
@@ -164,10 +164,10 @@ bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk,
                wake_up(wq);
 }
 
-/**
+/*
  *  Scsi_Host_template SCSI host template
  */
-/**
+/*
  * Scsi_Host template entry, returns BFAD PCI info.
  */
 static const char *
@@ -196,7 +196,7 @@ bfad_im_info(struct Scsi_Host *shost)
        return bfa_buf;
 }
 
-/**
+/*
  * Scsi_Host template entry, aborts the specified SCSI command.
  *
  * Returns: SUCCESS or FAILED.
@@ -280,7 +280,7 @@ out:
        return rc;
 }
 
-/**
+/*
  * Scsi_Host template entry, resets a LUN and abort its all commands.
  *
  * Returns: SUCCESS or FAILED.
@@ -319,7 +319,7 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd)
                goto out;
        }
 
-       /**
+       /*
         * Set host_scribble to NULL to avoid aborting a task command
         * if happens.
         */
@@ -346,7 +346,7 @@ out:
        return rc;
 }
 
-/**
+/*
  * Scsi_Host template entry, resets the bus and abort all commands.
  */
 static int
@@ -396,7 +396,7 @@ bfad_im_reset_bus_handler(struct scsi_cmnd *cmnd)
        return SUCCESS;
 }
 
-/**
+/*
  * Scsi_Host template entry slave_destroy.
  */
 static void
@@ -406,11 +406,11 @@ bfad_im_slave_destroy(struct scsi_device *sdev)
        return;
 }
 
-/**
+/*
  *  BFA FCS itnim callbacks
  */
 
-/**
+/*
  * BFA FCS itnim alloc callback, after successful PRLI
  * Context: Interrupt
  */
@@ -433,7 +433,7 @@ bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim,
        bfad->bfad_flags |= BFAD_RPORT_ONLINE;
 }
 
-/**
+/*
  * BFA FCS itnim free callback.
  * Context: Interrupt. bfad_lock is held
  */
@@ -471,7 +471,7 @@ bfa_fcb_itnim_free(struct bfad_s *bfad, struct bfad_itnim_s *itnim_drv)
                queue_work(im->drv_workq, &itnim_drv->itnim_work);
 }
 
-/**
+/*
  * BFA FCS itnim online callback.
  * Context: Interrupt. bfad_lock is held
  */
@@ -492,7 +492,7 @@ bfa_fcb_itnim_online(struct bfad_itnim_s *itnim_drv)
                queue_work(im->drv_workq, &itnim_drv->itnim_work);
 }
 
-/**
+/*
  * BFA FCS itnim offline callback.
  * Context: Interrupt. bfad_lock is held
  */
@@ -519,7 +519,7 @@ bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv)
                queue_work(im->drv_workq, &itnim_drv->itnim_work);
 }
 
-/**
+/*
  * Allocate a Scsi_Host for a port.
  */
 int
@@ -751,7 +751,7 @@ bfad_os_thread_workq(struct bfad_s *bfad)
        return BFA_STATUS_OK;
 }
 
-/**
+/*
  * Scsi_Host template entry.
  *
  * Description:
@@ -896,7 +896,7 @@ bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id)
        return NULL;
 }
 
-/**
+/*
  * Scsi_Host template entry slave_alloc
  */
 static int
@@ -915,12 +915,16 @@ bfad_im_slave_alloc(struct scsi_device *sdev)
 static u32
 bfad_im_supported_speeds(struct bfa_s *bfa)
 {
-       struct bfa_ioc_attr_s ioc_attr;
+       struct bfa_ioc_attr_s *ioc_attr;
        u32 supported_speed = 0;
 
-       bfa_get_attr(bfa, &ioc_attr);
-       if (ioc_attr.adapter_attr.max_speed == BFA_PORT_SPEED_8GBPS) {
-               if (ioc_attr.adapter_attr.is_mezz) {
+       ioc_attr = kzalloc(sizeof(struct bfa_ioc_attr_s), GFP_KERNEL);
+       if (!ioc_attr)
+               return 0;
+
+       bfa_get_attr(bfa, ioc_attr);
+       if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_8GBPS) {
+               if (ioc_attr->adapter_attr.is_mezz) {
                        supported_speed |= FC_PORTSPEED_8GBIT |
                                FC_PORTSPEED_4GBIT |
                                FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT;
@@ -929,12 +933,13 @@ bfad_im_supported_speeds(struct bfa_s *bfa)
                                FC_PORTSPEED_4GBIT |
                                FC_PORTSPEED_2GBIT;
                }
-       } else if (ioc_attr.adapter_attr.max_speed == BFA_PORT_SPEED_4GBPS) {
+       } else if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_4GBPS) {
                supported_speed |=  FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT |
                                FC_PORTSPEED_1GBIT;
-       } else if (ioc_attr.adapter_attr.max_speed == BFA_PORT_SPEED_10GBPS) {
+       } else if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_10GBPS) {
                supported_speed |= FC_PORTSPEED_10GBIT;
        }
+       kfree(ioc_attr);
        return supported_speed;
 }
 
@@ -944,14 +949,13 @@ bfad_os_fc_host_init(struct bfad_im_port_s *im_port)
        struct Scsi_Host *host = im_port->shost;
        struct bfad_s         *bfad = im_port->bfad;
        struct bfad_port_s    *port = im_port->port;
-       struct bfa_port_attr_s pattr;
-       struct bfa_lport_attr_s port_attr;
        char symname[BFA_SYMNAME_MAXLEN];
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
 
        fc_host_node_name(host) =
-               bfa_os_htonll((bfa_fcs_lport_get_nwwn(port->fcs_port)));
+               cpu_to_be64((bfa_fcs_lport_get_nwwn(port->fcs_port)));
        fc_host_port_name(host) =
-               bfa_os_htonll((bfa_fcs_lport_get_pwwn(port->fcs_port)));
+               cpu_to_be64((bfa_fcs_lport_get_pwwn(port->fcs_port)));
        fc_host_max_npiv_vports(host) = bfa_lps_get_max_vport(&bfad->bfa);
 
        fc_host_supported_classes(host) = FC_COS_CLASS3;
@@ -964,15 +968,12 @@ bfad_os_fc_host_init(struct bfad_im_port_s *im_port)
        /* For fibre channel services type 0x20 */
        fc_host_supported_fc4s(host)[7] = 1;
 
-       bfa_fcs_lport_get_attr(&bfad->bfa_fcs.fabric.bport, &port_attr);
-       strncpy(symname, port_attr.port_cfg.sym_name.symname,
+       strncpy(symname, bfad->bfa_fcs.fabric.bport.port_cfg.sym_name.symname,
                BFA_SYMNAME_MAXLEN);
        sprintf(fc_host_symbolic_name(host), "%s", symname);
 
        fc_host_supported_speeds(host) = bfad_im_supported_speeds(&bfad->bfa);
-
-       bfa_fcport_get_attr(&bfad->bfa, &pattr);
-       fc_host_maxframe_size(host) = pattr.pport_cfg.maxfrsize;
+       fc_host_maxframe_size(host) = fcport->cfg.maxfrsize;
 }
 
 static void
@@ -983,9 +984,9 @@ bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim)
        struct bfad_itnim_data_s *itnim_data;
 
        rport_ids.node_name =
-               bfa_os_htonll(bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim));
+               cpu_to_be64(bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim));
        rport_ids.port_name =
-               bfa_os_htonll(bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim));
+               cpu_to_be64(bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim));
        rport_ids.port_id =
                bfa_os_hton3b(bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim));
        rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
@@ -1015,7 +1016,7 @@ bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim)
        return;
 }
 
-/**
+/*
  * Work queue handler using FC transport service
 * Context: kernel
  */
@@ -1115,7 +1116,7 @@ bfad_im_itnim_work_handler(struct work_struct *work)
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 }
 
-/**
+/*
  * Scsi_Host template entry, queue a SCSI command to the BFAD.
  */
 static int
index 85f2224a5733cf2847377c103c818d1fb545632e..58796d1284b70ae2b49b238d5b2e66737ca5d1a3 100644 (file)
@@ -23,7 +23,7 @@
 
 #pragma pack(1)
 
-/**
+/*
  * BFI FW image type
  */
 #define        BFI_FLASH_CHUNK_SZ                      256     /*  Flash chunk size */
@@ -35,7 +35,7 @@ enum {
        BFI_IMAGE_MAX,
 };
 
-/**
+/*
  * Msg header common to all msgs
  */
 struct bfi_mhdr_s {
@@ -68,7 +68,7 @@ struct bfi_mhdr_s {
 #define BFI_I2H_OPCODE_BASE    128
 #define BFA_I2HM(_x)           ((_x) + BFI_I2H_OPCODE_BASE)
 
-/**
+/*
  ****************************************************************************
  *
  * Scatter Gather Element and Page definition
@@ -79,7 +79,7 @@ struct bfi_mhdr_s {
 #define BFI_SGE_INLINE 1
 #define BFI_SGE_INLINE_MAX     (BFI_SGE_INLINE + 1)
 
-/**
+/*
  * SG Flags
  */
 enum {
@@ -90,7 +90,7 @@ enum {
        BFI_SGE_PGDLEN          = 2,    /*  cumulative data length for page */
 };
 
-/**
+/*
  * DMA addresses
  */
 union bfi_addr_u {
@@ -100,7 +100,7 @@ union bfi_addr_u {
        } a32;
 };
 
-/**
+/*
  * Scatter Gather Element
  */
 struct bfi_sge_s {
@@ -116,7 +116,7 @@ struct bfi_sge_s {
        union bfi_addr_u sga;
 };
 
-/**
+/*
  * Scatter Gather Page
  */
 #define BFI_SGPG_DATA_SGES             7
@@ -139,7 +139,7 @@ struct bfi_msg_s {
        u32     pl[BFI_LMSG_PL_WSZ];
 };
 
-/**
+/*
  * Mailbox message structure
  */
 #define BFI_MBMSG_SZ           7
@@ -148,7 +148,7 @@ struct bfi_mbmsg_s {
        u32             pl[BFI_MBMSG_SZ];
 };
 
-/**
+/*
  * Message Classes
  */
 enum bfi_mclass {
@@ -186,7 +186,7 @@ enum bfi_mclass {
 #define BFI_BOOT_LOADER_BIOS           1
 #define BFI_BOOT_LOADER_UEFI           2
 
-/**
+/*
  *----------------------------------------------------------------------
  *                             IOC
  *----------------------------------------------------------------------
@@ -208,7 +208,7 @@ enum bfi_ioc_i2h_msgs {
        BFI_IOC_I2H_HBEAT               = BFA_I2HM(5),
 };
 
-/**
+/*
  * BFI_IOC_H2I_GETATTR_REQ message
  */
 struct bfi_ioc_getattr_req_s {
@@ -242,7 +242,7 @@ struct bfi_ioc_attr_s {
        u32     card_type;      /*  card type                   */
 };
 
-/**
+/*
  * BFI_IOC_I2H_GETATTR_REPLY message
  */
 struct bfi_ioc_getattr_reply_s {
@@ -251,19 +251,19 @@ struct bfi_ioc_getattr_reply_s {
        u8                      rsvd[3];
 };
 
-/**
+/*
  * Firmware memory page offsets
  */
 #define BFI_IOC_SMEM_PG0_CB    (0x40)
 #define BFI_IOC_SMEM_PG0_CT    (0x180)
 
-/**
+/*
  * Firmware statistic offset
  */
 #define BFI_IOC_FWSTATS_OFF    (0x6B40)
 #define BFI_IOC_FWSTATS_SZ     (4096)
 
-/**
+/*
  * Firmware trace offset
  */
 #define BFI_IOC_TRC_OFF                (0x4b00)
@@ -280,7 +280,7 @@ struct bfi_ioc_image_hdr_s {
        u32     md5sum[BFI_IOC_MD5SUM_SZ];
 };
 
-/**
+/*
  *  BFI_IOC_I2H_READY_EVENT message
  */
 struct bfi_ioc_rdy_event_s {
@@ -294,7 +294,7 @@ struct bfi_ioc_hbeat_s {
        u32        hb_count;    /*  current heart beat count    */
 };
 
-/**
+/*
  * IOC hardware/firmware state
  */
 enum bfi_ioc_state {
@@ -340,7 +340,7 @@ enum {
        ((__adap_type) & (BFI_ADAPTER_TTV | BFI_ADAPTER_PROTO | \
                        BFI_ADAPTER_UNSUPP))
 
-/**
+/*
  * BFI_IOC_H2I_ENABLE_REQ & BFI_IOC_H2I_DISABLE_REQ messages
  */
 struct bfi_ioc_ctrl_req_s {
@@ -352,7 +352,7 @@ struct bfi_ioc_ctrl_req_s {
 #define bfi_ioc_enable_req_t struct bfi_ioc_ctrl_req_s;
 #define bfi_ioc_disable_req_t struct bfi_ioc_ctrl_req_s;
 
-/**
+/*
  * BFI_IOC_I2H_ENABLE_REPLY & BFI_IOC_I2H_DISABLE_REPLY messages
  */
 struct bfi_ioc_ctrl_reply_s {
@@ -364,7 +364,7 @@ struct bfi_ioc_ctrl_reply_s {
 #define bfi_ioc_disable_reply_t struct bfi_ioc_ctrl_reply_s;
 
 #define BFI_IOC_MSGSZ   8
-/**
+/*
  * H2I Messages
  */
 union bfi_ioc_h2i_msg_u {
@@ -375,7 +375,7 @@ union bfi_ioc_h2i_msg_u {
        u32                     mboxmsg[BFI_IOC_MSGSZ];
 };
 
-/**
+/*
  * I2H Messages
  */
 union bfi_ioc_i2h_msg_u {
@@ -385,7 +385,7 @@ union bfi_ioc_i2h_msg_u {
 };
 
 
-/**
+/*
  *----------------------------------------------------------------------
  *                             PBC
  *----------------------------------------------------------------------
@@ -394,7 +394,7 @@ union bfi_ioc_i2h_msg_u {
 #define BFI_PBC_MAX_BLUNS      8
 #define BFI_PBC_MAX_VPORTS     16
 
-/**
+/*
  * PBC boot lun configuration
  */
 struct bfi_pbc_blun_s {
@@ -402,7 +402,7 @@ struct bfi_pbc_blun_s {
        lun_t           tgt_lun;
 };
 
-/**
+/*
  * PBC virtual port configuration
  */
 struct bfi_pbc_vport_s {
@@ -410,7 +410,7 @@ struct bfi_pbc_vport_s {
        wwn_t           vp_nwwn;
 };
 
-/**
+/*
  * BFI pre-boot configuration information
  */
 struct bfi_pbc_s {
@@ -427,7 +427,7 @@ struct bfi_pbc_s {
        struct bfi_pbc_vport_s vport[BFI_PBC_MAX_VPORTS];
 };
 
-/**
+/*
  *----------------------------------------------------------------------
  *                             MSGQ
  *----------------------------------------------------------------------
@@ -531,7 +531,7 @@ enum bfi_port_i2h {
        BFI_PORT_I2H_CLEAR_STATS_RSP    = BFA_I2HM(4),
 };
 
-/**
+/*
  * Generic REQ type
  */
 struct bfi_port_generic_req_s {
@@ -540,7 +540,7 @@ struct bfi_port_generic_req_s {
        u32     rsvd;
 };
 
-/**
+/*
  * Generic RSP type
  */
 struct bfi_port_generic_rsp_s {
@@ -550,7 +550,7 @@ struct bfi_port_generic_rsp_s {
        u32     msgtag;         /*  msgtag for reply                */
 };
 
-/**
+/*
  * BFI_PORT_H2I_GET_STATS_REQ
  */
 struct bfi_port_get_stats_req_s {
index 69ac85f9e938c9f8aa4d5b42eb186f05f21a2f9c..fa9f6fb9d45b0decc0920d88439b89c7bc37dbe5 100644 (file)
@@ -41,7 +41,7 @@ struct bfi_iocfc_cfg_s {
        u16     rsvd_1;
        u32     endian_sig;     /*  endian signature of host     */
 
-       /**
+       /*
         * Request and response circular queue base addresses, size and
         * shadow index pointers.
         */
@@ -58,7 +58,7 @@ struct bfi_iocfc_cfg_s {
        struct bfa_iocfc_intr_attr_s intr_attr; /*  IOC interrupt attributes */
 };
 
-/**
+/*
  * Boot target wwn information for this port. This contains either the stored
  * or discovered boot target port wwns for the port.
  */
@@ -75,7 +75,7 @@ struct bfi_iocfc_cfgrsp_s {
        struct bfi_pbc_s                pbc_cfg;
 };
 
-/**
+/*
  * BFI_IOCFC_H2I_CFG_REQ message
  */
 struct bfi_iocfc_cfg_req_s {
@@ -84,7 +84,7 @@ struct bfi_iocfc_cfg_req_s {
 };
 
 
-/**
+/*
  * BFI_IOCFC_I2H_CFG_REPLY message
  */
 struct bfi_iocfc_cfg_reply_s {
@@ -95,7 +95,7 @@ struct bfi_iocfc_cfg_reply_s {
 };
 
 
-/**
+/*
  * BFI_IOCFC_H2I_SET_INTR_REQ message
  */
 struct bfi_iocfc_set_intr_req_s {
@@ -107,7 +107,7 @@ struct bfi_iocfc_set_intr_req_s {
 };
 
 
-/**
+/*
  * BFI_IOCFC_H2I_UPDATEQ_REQ message
  */
 struct bfi_iocfc_updateq_req_s {
@@ -119,7 +119,7 @@ struct bfi_iocfc_updateq_req_s {
 };
 
 
-/**
+/*
  * BFI_IOCFC_I2H_UPDATEQ_RSP message
  */
 struct bfi_iocfc_updateq_rsp_s {
@@ -129,7 +129,7 @@ struct bfi_iocfc_updateq_rsp_s {
 };
 
 
-/**
+/*
  * H2I Messages
  */
 union bfi_iocfc_h2i_msg_u {
@@ -140,7 +140,7 @@ union bfi_iocfc_h2i_msg_u {
 };
 
 
-/**
+/*
  * I2H Messages
  */
 union bfi_iocfc_i2h_msg_u {
@@ -173,7 +173,7 @@ enum bfi_fcport_i2h {
 };
 
 
-/**
+/*
  * Generic REQ type
  */
 struct bfi_fcport_req_s {
@@ -181,7 +181,7 @@ struct bfi_fcport_req_s {
        u32        msgtag;      /*  msgtag for reply                */
 };
 
-/**
+/*
  * Generic RSP type
  */
 struct bfi_fcport_rsp_s {
@@ -191,7 +191,7 @@ struct bfi_fcport_rsp_s {
        u32        msgtag;      /*  msgtag for reply                */
 };
 
-/**
+/*
  * BFI_FCPORT_H2I_ENABLE_REQ
  */
 struct bfi_fcport_enable_req_s {
@@ -205,7 +205,7 @@ struct bfi_fcport_enable_req_s {
        u32        rsvd2;
 };
 
-/**
+/*
  * BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ
  */
 struct bfi_fcport_set_svc_params_req_s {
@@ -214,7 +214,7 @@ struct bfi_fcport_set_svc_params_req_s {
        u16        rsvd;
 };
 
-/**
+/*
  * BFI_FCPORT_I2H_EVENT
  */
 struct bfi_fcport_event_s {
@@ -222,7 +222,7 @@ struct bfi_fcport_event_s {
        struct bfa_port_link_s  link_state;
 };
 
-/**
+/*
  * BFI_FCPORT_I2H_TRUNK_SCN
  */
 struct bfi_fcport_trunk_link_s {
@@ -243,7 +243,7 @@ struct bfi_fcport_trunk_scn_s {
        struct bfi_fcport_trunk_link_s tlink[BFI_FCPORT_MAX_LINKS];
 };
 
-/**
+/*
  * fcport H2I message
  */
 union bfi_fcport_h2i_msg_u {
@@ -255,7 +255,7 @@ union bfi_fcport_h2i_msg_u {
        struct bfi_fcport_req_s                 *pstatsclear;
 };
 
-/**
+/*
  * fcport I2H message
  */
 union bfi_fcport_i2h_msg_u {
@@ -279,7 +279,7 @@ enum bfi_fcxp_i2h {
 
 #define BFA_FCXP_MAX_SGES      2
 
-/**
+/*
  * FCXP send request structure
  */
 struct bfi_fcxp_send_req_s {
@@ -299,7 +299,7 @@ struct bfi_fcxp_send_req_s {
        struct bfi_sge_s   rsp_sge[BFA_FCXP_MAX_SGES];  /*  response buf   */
 };
 
-/**
+/*
  * FCXP send response structure
  */
 struct bfi_fcxp_send_rsp_s {
@@ -565,14 +565,14 @@ enum bfi_ioim_i2h {
        BFI_IOIM_I2H_IOABORT_RSP = BFA_I2HM(2), /*  ABORT rsp    */
 };
 
-/**
+/*
  * IO command DIF info
  */
 struct bfi_ioim_dif_s {
        u32     dif_info[4];
 };
 
-/**
+/*
  * FCP IO messages overview
  *
  * @note
@@ -587,7 +587,7 @@ struct bfi_ioim_req_s {
        u16     rport_hdl;      /*  itnim/rport firmware handle */
        struct fcp_cmnd_s       cmnd;   /*  IO request info     */
 
-       /**
+       /*
         * SG elements array within the IO request must be double word
         * aligned. This aligment is required to optimize SGM setup for the IO.
         */
@@ -598,7 +598,7 @@ struct bfi_ioim_req_s {
        struct bfi_ioim_dif_s  dif;
 };
 
-/**
+/*
  *     This table shows various IO status codes from firmware and their
  *     meaning. Host driver can use these status codes to further process
  *     IO completions.
@@ -684,7 +684,7 @@ enum bfi_ioim_status {
 };
 
 #define BFI_IOIM_SNSLEN        (256)
-/**
+/*
  * I/O response message
  */
 struct bfi_ioim_rsp_s {
@@ -746,7 +746,7 @@ enum bfi_tskim_status {
        BFI_TSKIM_STS_NOT_SUPP = 4,
        BFI_TSKIM_STS_FAILED    = 5,
 
-       /**
+       /*
         * Defined by BFA
         */
        BFI_TSKIM_STS_TIMEOUT  = 10,    /*  TM request timedout */
index 99f2b8c5dd6310420b61df64af22649bcf41b296..8c04fada710b441713f95a1e5bc43fef49728e6e 100644 (file)
@@ -692,6 +692,9 @@ static void do_act_open_rpl(struct cxgbi_device *cdev, struct sk_buff *skb)
                &csk->daddr.sin_addr.s_addr, ntohs(csk->daddr.sin_port),
                atid, tid, status, csk, csk->state, csk->flags);
 
+       if (status == CPL_ERR_RTX_NEG_ADVICE)
+               goto rel_skb;
+
        if (status && status != CPL_ERR_TCAM_FULL &&
            status != CPL_ERR_CONN_EXIST &&
            status != CPL_ERR_ARP_MISS)
index b9bcfa4c7d261dd5e1e13725459487d2dfe638f6..5be3ae15cb71b858a7402b06a6c10923facd1edf 100644 (file)
@@ -773,6 +773,8 @@ static const struct scsi_dh_devlist rdac_dev_list[] = {
        {"ENGENIO", "INF-01-00"},
        {"STK", "FLEXLINE 380"},
        {"SUN", "CSM100_R_FC"},
+       {"SUN", "STK6580_6780"},
+       {"SUN", "SUN_6180"},
        {NULL, NULL},
 };
 
index 844d618b84bdd51151c21bdd91dd9d0f9b100455..d23a538a9dfcca1e5bae286fb8305796dd6a8233 100644 (file)
@@ -117,7 +117,7 @@ static void fcoe_recv_frame(struct sk_buff *skb);
 
 static void fcoe_get_lesb(struct fc_lport *, struct fc_els_lesb *);
 
-module_param_call(create, fcoe_create, NULL, (void *)FIP_MODE_AUTO, S_IWUSR);
+module_param_call(create, fcoe_create, NULL, (void *)FIP_MODE_FABRIC, S_IWUSR);
 __MODULE_PARM_TYPE(create, "string");
 MODULE_PARM_DESC(create, " Creates fcoe instance on a ethernet interface");
 module_param_call(create_vn2vn, fcoe_create, NULL,
@@ -1243,7 +1243,6 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
        struct fcoe_interface *fcoe;
        struct fc_frame_header *fh;
        struct fcoe_percpu_s *fps;
-       struct fcoe_port *port;
        struct ethhdr *eh;
        unsigned int cpu;
 
@@ -1262,16 +1261,7 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
                        skb_tail_pointer(skb), skb_end_pointer(skb),
                        skb->csum, skb->dev ? skb->dev->name : "<NULL>");
 
-       /* check for mac addresses */
        eh = eth_hdr(skb);
-       port = lport_priv(lport);
-       if (compare_ether_addr(eh->h_dest, port->data_src_addr) &&
-           compare_ether_addr(eh->h_dest, fcoe->ctlr.ctl_src_addr) &&
-           compare_ether_addr(eh->h_dest, (u8[6])FC_FCOE_FLOGI_MAC)) {
-               FCOE_NETDEV_DBG(netdev, "wrong destination mac address:%pM\n",
-                               eh->h_dest);
-               goto err;
-       }
 
        if (is_fip_mode(&fcoe->ctlr) &&
            compare_ether_addr(eh->h_source, fcoe->ctlr.dest_addr)) {
@@ -1291,6 +1281,12 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
        skb_set_transport_header(skb, sizeof(struct fcoe_hdr));
        fh = (struct fc_frame_header *) skb_transport_header(skb);
 
+       if (ntoh24(&eh->h_dest[3]) != ntoh24(fh->fh_d_id)) {
+               FCOE_NETDEV_DBG(netdev, "FC frame d_id mismatch with MAC:%pM\n",
+                               eh->h_dest);
+               goto err;
+       }
+
        fr = fcoe_dev_from_skb(skb);
        fr->fr_dev = lport;
        fr->ptype = ptype;
index aa503d83092a09eb0b69ea1ca76fd227807bd39a..bc17c71232023c7d3b830a541df976de7146a72c 100644 (file)
@@ -2296,7 +2296,7 @@ static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
 {
        struct fip_header *fiph;
        enum fip_vn2vn_subcode sub;
-       union {
+       struct {
                struct fc_rport_priv rdata;
                struct fcoe_rport frport;
        } buf;
index 5a3f93101017b601fe98b2bbf12d9b55fd27152b..841101846b88fe98e55a6c601b013ef9119cdf4a 100644 (file)
@@ -4177,6 +4177,14 @@ static int ioc_general(void __user *arg, char *cmnd)
     ha = gdth_find_ha(gen.ionode);
     if (!ha)
         return -EFAULT;
+
+    if (gen.data_len > INT_MAX)
+        return -EINVAL;
+    if (gen.sense_len > INT_MAX)
+        return -EINVAL;
+    if (gen.data_len + gen.sense_len > INT_MAX)
+        return -EINVAL;
+
     if (gen.data_len + gen.sense_len != 0) {
         if (!(buf = gdth_ioctl_alloc(ha, gen.data_len + gen.sense_len,
                                      FALSE, &paddr)))
index df9a12c8b373144618ff051cdb38498648df2df5..fa60d7df44bed7154adf9aa784cecc937db64d23 100644 (file)
@@ -9025,6 +9025,8 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574D, 0, 0, 0 },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2,
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B2, 0, 0, 0 },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C4, 0, 0, 0 },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B4, 0, 0, 0 },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
index aa8bb2f2c6ee286c2fa73c734d37cb8f26573138..b28a00f1082c3e3bbab4e412725030626890652c 100644 (file)
@@ -82,6 +82,7 @@
 
 #define IPR_SUBS_DEV_ID_57B4    0x033B
 #define IPR_SUBS_DEV_ID_57B2    0x035F
+#define IPR_SUBS_DEV_ID_57C4    0x0354
 #define IPR_SUBS_DEV_ID_57C6    0x0357
 #define IPR_SUBS_DEV_ID_57CC    0x035C
 
index 32f67c4b03fc014b8b47935a761a9feb6bdfa59a..911b2736cafae204379b8db7f18767b788d79bc3 100644 (file)
@@ -684,10 +684,9 @@ void fc_disc_stop(struct fc_lport *lport)
 {
        struct fc_disc *disc = &lport->disc;
 
-       if (disc) {
+       if (disc->pending)
                cancel_delayed_work_sync(&disc->disc_work);
-               fc_disc_stop_rports(disc);
-       }
+       fc_disc_stop_rports(disc);
 }
 
 /**
index c797f6b48f05bccff273e06964c0dc06508de174..e340373b509b6528ea0602d410eb902c3b233321 100644 (file)
@@ -58,8 +58,7 @@ struct kmem_cache *scsi_pkt_cachep;
 #define FC_SRB_WRITE           (1 << 0)
 
 /*
- * The SCp.ptr should be tested and set under the host lock. NULL indicates
- * that the command has been retruned to the scsi layer.
+ * The SCp.ptr should be tested and set under the scsi_pkt_queue lock
  */
 #define CMD_SP(Cmnd)               ((struct fc_fcp_pkt *)(Cmnd)->SCp.ptr)
 #define CMD_ENTRY_STATUS(Cmnd)     ((Cmnd)->SCp.have_data_in)
@@ -1880,8 +1879,6 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
 
        lport = fsp->lp;
        si = fc_get_scsi_internal(lport);
-       if (!fsp->cmd)
-               return;
 
        /*
         * if can_queue ramp down is done then try can_queue ramp up
@@ -1891,11 +1888,6 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
                fc_fcp_can_queue_ramp_up(lport);
 
        sc_cmd = fsp->cmd;
-       fsp->cmd = NULL;
-
-       if (!sc_cmd->SCp.ptr)
-               return;
-
        CMD_SCSI_STATUS(sc_cmd) = fsp->cdb_status;
        switch (fsp->status_code) {
        case FC_COMPLETE:
@@ -1971,15 +1963,13 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
                break;
        }
 
-       if (lport->state != LPORT_ST_READY && fsp->status_code != FC_COMPLETE) {
-               sc_cmd->result = (DID_REQUEUE << 16);
-               FC_FCP_DBG(fsp, "Returning DID_REQUEUE to scsi-ml\n");
-       }
+       if (lport->state != LPORT_ST_READY && fsp->status_code != FC_COMPLETE)
+               sc_cmd->result = (DID_TRANSPORT_DISRUPTED << 16);
 
        spin_lock_irqsave(&si->scsi_queue_lock, flags);
        list_del(&fsp->list);
-       spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
        sc_cmd->SCp.ptr = NULL;
+       spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
        sc_cmd->scsi_done(sc_cmd);
 
        /* release ref from initial allocation in queue command */
@@ -1997,6 +1987,7 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd)
 {
        struct fc_fcp_pkt *fsp;
        struct fc_lport *lport;
+       struct fc_fcp_internal *si;
        int rc = FAILED;
        unsigned long flags;
 
@@ -2006,7 +1997,8 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd)
        else if (!lport->link_up)
                return rc;
 
-       spin_lock_irqsave(lport->host->host_lock, flags);
+       si = fc_get_scsi_internal(lport);
+       spin_lock_irqsave(&si->scsi_queue_lock, flags);
        fsp = CMD_SP(sc_cmd);
        if (!fsp) {
                /* command completed while scsi eh was setting up */
@@ -2015,7 +2007,7 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd)
        }
        /* grab a ref so the fsp and sc_cmd cannot be relased from under us */
        fc_fcp_pkt_hold(fsp);
-       spin_unlock_irqrestore(lport->host->host_lock, flags);
+       spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
 
        if (fc_fcp_lock_pkt(fsp)) {
                /* completed while we were waiting for timer to be deleted */
index d9b6e11b0e884b122cfe4d7b6fc2888e5e6c507d..9be63edbf8fb9095624222f7dc6398957e0abd28 100644 (file)
@@ -1447,13 +1447,7 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
        }
 
        did = fc_frame_did(fp);
-
-       if (!did) {
-               FC_LPORT_DBG(lport, "Bad FLOGI response\n");
-               goto out;
-       }
-
-       if (fc_frame_payload_op(fp) == ELS_LS_ACC) {
+       if (fc_frame_payload_op(fp) == ELS_LS_ACC && did) {
                flp = fc_frame_payload_get(fp, sizeof(*flp));
                if (flp) {
                        mfs = ntohs(flp->fl_csp.sp_bb_data) &
@@ -1492,8 +1486,10 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
                                fc_lport_enter_dns(lport);
                        }
                }
-       } else
+       } else {
+               FC_LPORT_DBG(lport, "FLOGI RJT or bad response\n");
                fc_lport_error(lport, fp);
+       }
 
 out:
        fc_frame_free(fp);
index b9f2286fe0cbc9ef849cb8e2a713d9d0b11776f7..a84ef13ed74adf2a0e0d1dd81c644b2f3c9514a7 100644 (file)
@@ -196,9 +196,9 @@ static const char *fc_rport_state(struct fc_rport_priv *rdata)
 void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
 {
        if (timeout)
-               rport->dev_loss_tmo = timeout + 5;
+               rport->dev_loss_tmo = timeout;
        else
-               rport->dev_loss_tmo = 30;
+               rport->dev_loss_tmo = 1;
 }
 EXPORT_SYMBOL(fc_set_rport_loss_tmo);
 
index a50aa03b8ac1826c13d8acb22b6bb613c91e024e..196de40b906c487c0287b56ac3c27c5f4b66a5ee 100644 (file)
@@ -202,9 +202,12 @@ struct lpfc_stats {
        uint32_t elsRcvPRLO;
        uint32_t elsRcvPRLI;
        uint32_t elsRcvLIRR;
+       uint32_t elsRcvRLS;
        uint32_t elsRcvRPS;
        uint32_t elsRcvRPL;
        uint32_t elsRcvRRQ;
+       uint32_t elsRcvRTV;
+       uint32_t elsRcvECHO;
        uint32_t elsXmitFLOGI;
        uint32_t elsXmitFDISC;
        uint32_t elsXmitPLOGI;
@@ -549,9 +552,11 @@ struct lpfc_hba {
 #define ELS_XRI_ABORT_EVENT    0x40
 #define ASYNC_EVENT            0x80
 #define LINK_DISABLED          0x100 /* Link disabled by user */
-#define FCF_DISC_INPROGRESS    0x200 /* FCF discovery in progress */
-#define HBA_FIP_SUPPORT                0x400 /* FIP support in HBA */
-#define HBA_AER_ENABLED                0x800 /* AER enabled with HBA */
+#define FCF_TS_INPROG           0x200 /* FCF table scan in progress */
+#define FCF_RR_INPROG           0x400 /* FCF roundrobin flogi in progress */
+#define HBA_FIP_SUPPORT                0x800 /* FIP support in HBA */
+#define HBA_AER_ENABLED                0x1000 /* AER enabled with HBA */
+#define HBA_DEVLOSS_TMO         0x2000 /* HBA in devloss timeout */
        uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/
        struct lpfc_dmabuf slim2p;
 
@@ -573,6 +578,7 @@ struct lpfc_hba {
        /* These fields used to be binfo */
        uint32_t fc_pref_DID;   /* preferred D_ID */
        uint8_t  fc_pref_ALPA;  /* preferred AL_PA */
+       uint32_t fc_edtovResol; /* E_D_TOV timer resolution */
        uint32_t fc_edtov;      /* E_D_TOV timer value */
        uint32_t fc_arbtov;     /* ARB_TOV timer value */
        uint32_t fc_ratov;      /* R_A_TOV timer value */
index f681eea57730a794fccaf792243b8a4791abcee3..c1cbec01345d0849a027748cdad9425e72094356 100644 (file)
@@ -3789,8 +3789,13 @@ sysfs_mbox_read(struct file *filp, struct kobject *kobj,
                        break;
                case MBX_SECURITY_MGMT:
                case MBX_AUTH_PORT:
-                       if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
+                       if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) {
+                               printk(KERN_WARNING "mbox_read:Command 0x%x "
+                                      "is not permitted\n", pmb->mbxCommand);
+                               sysfs_mbox_idle(phba);
+                               spin_unlock_irq(&phba->hbalock);
                                return -EPERM;
+                       }
                        break;
                case MBX_READ_SPARM64:
                case MBX_READ_LA:
index f5d60b55f53a37d5d8e6b2a12b9fb8107771c131..7260c3af555a0723924553fb362cb88aee742cd5 100644 (file)
@@ -3142,12 +3142,12 @@ lpfc_bsg_menlo_cmd_cmp(struct lpfc_hba *phba,
        job = menlo->set_job;
        job->dd_data = NULL; /* so timeout handler does not reply */
 
-       spin_lock_irqsave(&phba->hbalock, flags);
+       spin_lock(&phba->hbalock);
        cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
        if (cmdiocbq->context2 && rspiocbq)
                memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
                       &rspiocbq->iocb, sizeof(IOCB_t));
-       spin_unlock_irqrestore(&phba->hbalock, flags);
+       spin_unlock(&phba->hbalock);
 
        bmp = menlo->bmp;
        rspiocbq = menlo->rspiocbq;
index 03f4ddc185723f94520e112df291cc266b8c45d3..a5f5a093a8a46752e5c802da8a593de4510e7e6e 100644 (file)
@@ -44,6 +44,8 @@ int lpfc_reg_rpi(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
 void lpfc_set_var(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
 void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
 void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
+void lpfc_sli4_unreg_all_rpis(struct lpfc_vport *);
+
 void lpfc_reg_vpi(struct lpfc_vport *, LPFC_MBOXQ_t *);
 void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *,
                        struct lpfc_nodelist *);
@@ -229,6 +231,7 @@ void lpfc_sli4_fcf_dead_failthrough(struct lpfc_hba *);
 uint16_t lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *);
 int lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *, uint16_t);
 void lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *, uint16_t);
+int lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *, uint16_t);
 
 int lpfc_mem_alloc(struct lpfc_hba *, int align);
 void lpfc_mem_free(struct lpfc_hba *);
@@ -271,6 +274,7 @@ int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,
 void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t);
 void lpfc_sli_bemem_bcopy(void *, void *, uint32_t);
 void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *);
+void lpfc_sli_hba_iocb_abort(struct lpfc_hba *);
 void lpfc_sli_flush_fcp_rings(struct lpfc_hba *);
 int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
                             struct lpfc_dmabuf *);
index e6ca12f6c6cb5063857f30f7b3e01b6e5587f14d..884f4d321799cffda5bb5ea56295d4166fb0b32c 100644 (file)
@@ -177,15 +177,18 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
                 (elscmd == ELS_CMD_LOGO)))
                switch (elscmd) {
                case ELS_CMD_FLOGI:
-               elsiocb->iocb_flag |= ((ELS_ID_FLOGI << LPFC_FIP_ELS_ID_SHIFT)
+               elsiocb->iocb_flag |=
+                       ((LPFC_ELS_ID_FLOGI << LPFC_FIP_ELS_ID_SHIFT)
                                        & LPFC_FIP_ELS_ID_MASK);
                break;
                case ELS_CMD_FDISC:
-               elsiocb->iocb_flag |= ((ELS_ID_FDISC << LPFC_FIP_ELS_ID_SHIFT)
+               elsiocb->iocb_flag |=
+                       ((LPFC_ELS_ID_FDISC << LPFC_FIP_ELS_ID_SHIFT)
                                        & LPFC_FIP_ELS_ID_MASK);
                break;
                case ELS_CMD_LOGO:
-               elsiocb->iocb_flag |= ((ELS_ID_LOGO << LPFC_FIP_ELS_ID_SHIFT)
+               elsiocb->iocb_flag |=
+                       ((LPFC_ELS_ID_LOGO << LPFC_FIP_ELS_ID_SHIFT)
                                        & LPFC_FIP_ELS_ID_MASK);
                break;
                }
@@ -517,18 +520,13 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        if (sp->cmn.edtovResolution)    /* E_D_TOV ticks are in nanoseconds */
                phba->fc_edtov = (phba->fc_edtov + 999999) / 1000000;
 
+       phba->fc_edtovResol = sp->cmn.edtovResolution;
        phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000;
 
        if (phba->fc_topology == TOPOLOGY_LOOP) {
                spin_lock_irq(shost->host_lock);
                vport->fc_flag |= FC_PUBLIC_LOOP;
                spin_unlock_irq(shost->host_lock);
-       } else {
-               /*
-                * If we are a N-port connected to a Fabric, fixup sparam's so
-                * logins to devices on remote loops work.
-                */
-               vport->fc_sparam.cmn.altBbCredit = 1;
        }
 
        vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
@@ -585,6 +583,10 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                        lpfc_unreg_rpi(vport, np);
                }
                lpfc_cleanup_pending_mbox(vport);
+
+               if (phba->sli_rev == LPFC_SLI_REV4)
+                       lpfc_sli4_unreg_all_rpis(vport);
+
                if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
                        lpfc_mbx_unreg_vpi(vport);
                        spin_lock_irq(shost->host_lock);
@@ -800,7 +802,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
        if (irsp->ulpStatus) {
                /*
-                * In case of FIP mode, perform round robin FCF failover
+                * In case of FIP mode, perform roundrobin FCF failover
                 * due to new FCF discovery
                 */
                if ((phba->hba_flag & HBA_FIP_SUPPORT) &&
@@ -808,48 +810,16 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                    (irsp->ulpStatus != IOSTAT_LOCAL_REJECT) &&
                    (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED)) {
                        lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS,
-                                       "2611 FLOGI failed on registered "
-                                       "FCF record fcf_index(%d), status: "
-                                       "x%x/x%x, tmo:x%x, trying to perform "
-                                       "round robin failover\n",
+                                       "2611 FLOGI failed on FCF (x%x), "
+                                       "status:x%x/x%x, tmo:x%x, perform "
+                                       "roundrobin FCF failover\n",
                                        phba->fcf.current_rec.fcf_indx,
                                        irsp->ulpStatus, irsp->un.ulpWord[4],
                                        irsp->ulpTimeout);
                        fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba);
-                       if (fcf_index == LPFC_FCOE_FCF_NEXT_NONE) {
-                               /*
-                                * Exhausted the eligible FCF record list,
-                                * fail through to retry FLOGI on current
-                                * FCF record.
-                                */
-                               lpfc_printf_log(phba, KERN_WARNING,
-                                               LOG_FIP | LOG_ELS,
-                                               "2760 Completed one round "
-                                               "of FLOGI FCF round robin "
-                                               "failover list, retry FLOGI "
-                                               "on currently registered "
-                                               "FCF index:%d\n",
-                                               phba->fcf.current_rec.fcf_indx);
-                       } else {
-                               lpfc_printf_log(phba, KERN_INFO,
-                                               LOG_FIP | LOG_ELS,
-                                               "2794 FLOGI FCF round robin "
-                                               "failover to FCF index x%x\n",
-                                               fcf_index);
-                               rc = lpfc_sli4_fcf_rr_read_fcf_rec(phba,
-                                                                  fcf_index);
-                               if (rc)
-                                       lpfc_printf_log(phba, KERN_WARNING,
-                                                       LOG_FIP | LOG_ELS,
-                                                       "2761 FLOGI round "
-                                                       "robin FCF failover "
-                                                       "read FCF failed "
-                                                       "rc:x%x, fcf_index:"
-                                                       "%d\n", rc,
-                                               phba->fcf.current_rec.fcf_indx);
-                               else
-                                       goto out;
-                       }
+                       rc = lpfc_sli4_fcf_rr_next_proc(vport, fcf_index);
+                       if (rc)
+                               goto out;
                }
 
                /* FLOGI failure */
@@ -939,6 +909,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        lpfc_nlp_put(ndlp);
                        spin_lock_irq(&phba->hbalock);
                        phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+                       phba->hba_flag &= ~(FCF_RR_INPROG | HBA_DEVLOSS_TMO);
                        spin_unlock_irq(&phba->hbalock);
                        goto out;
                }
@@ -947,13 +918,12 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        if (phba->hba_flag & HBA_FIP_SUPPORT)
                                lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP |
                                                LOG_ELS,
-                                               "2769 FLOGI successful on FCF "
-                                               "record: current_fcf_index:"
-                                               "x%x, terminate FCF round "
-                                               "robin failover process\n",
+                                               "2769 FLOGI to FCF (x%x) "
+                                               "completed successfully\n",
                                                phba->fcf.current_rec.fcf_indx);
                        spin_lock_irq(&phba->hbalock);
                        phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+                       phba->hba_flag &= ~(FCF_RR_INPROG | HBA_DEVLOSS_TMO);
                        spin_unlock_irq(&phba->hbalock);
                        goto out;
                }
@@ -1175,12 +1145,13 @@ lpfc_initial_flogi(struct lpfc_vport *vport)
                        return 0;
        }
 
-       if (lpfc_issue_els_flogi(vport, ndlp, 0))
+       if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
                /* This decrement of reference count to node shall kick off
                 * the release of the node.
                 */
                lpfc_nlp_put(ndlp);
-
+               return 0;
+       }
        return 1;
 }
 
@@ -1645,6 +1616,13 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
        memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
        sp = (struct serv_parm *) pcmd;
 
+       /*
+        * If we are a N-port connected to a Fabric, fix-up paramm's so logins
+        * to device on remote loops work.
+        */
+       if ((vport->fc_flag & FC_FABRIC) && !(vport->fc_flag & FC_PUBLIC_LOOP))
+               sp->cmn.altBbCredit = 1;
+
        if (sp->cmn.fcphLow < FC_PH_4_3)
                sp->cmn.fcphLow = FC_PH_4_3;
 
@@ -3925,6 +3903,64 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
        return 0;
 }
 
+/**
+ * lpfc_els_rsp_echo_acc - Issue echo acc response
+ * @vport: pointer to a virtual N_Port data structure.
+ * @data: pointer to echo data to return in the accept.
+ * @oldiocb: pointer to the original lpfc command iocb data structure.
+ * @ndlp: pointer to a node-list data structure.
+ *
+ * Return code
+ *   0 - Successfully issued acc echo response
+ *   1 - Failed to issue acc echo response
+ **/
+static int
+lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data,
+                     struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
+{
+       struct lpfc_hba  *phba = vport->phba;
+       struct lpfc_iocbq *elsiocb;
+       struct lpfc_sli *psli;
+       uint8_t *pcmd;
+       uint16_t cmdsize;
+       int rc;
+
+       psli = &phba->sli;
+       cmdsize = oldiocb->iocb.unsli3.rcvsli3.acc_len;
+
+       elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
+                                    ndlp->nlp_DID, ELS_CMD_ACC);
+       if (!elsiocb)
+               return 1;
+
+       elsiocb->iocb.ulpContext = oldiocb->iocb.ulpContext;    /* Xri */
+       /* Xmit ECHO ACC response tag <ulpIoTag> */
+       lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+                        "2876 Xmit ECHO ACC response tag x%x xri x%x\n",
+                        elsiocb->iotag, elsiocb->iocb.ulpContext);
+       pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+       *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
+       pcmd += sizeof(uint32_t);
+       memcpy(pcmd, data, cmdsize - sizeof(uint32_t));
+
+       lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+               "Issue ACC ECHO:  did:x%x flg:x%x",
+               ndlp->nlp_DID, ndlp->nlp_flag, 0);
+
+       phba->fc_stat.elsXmitACC++;
+       elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
+       lpfc_nlp_put(ndlp);
+       elsiocb->context1 = NULL;  /* Don't need ndlp for cmpl,
+                                   * it could be freed */
+
+       rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
+       if (rc == IOCB_ERROR) {
+               lpfc_els_free_iocb(phba, elsiocb);
+               return 1;
+       }
+       return 0;
+}
+
 /**
  * lpfc_els_disc_adisc - Issue remaining adisc iocbs to npr nodes of a vport
  * @vport: pointer to a host virtual N_Port data structure.
@@ -4683,6 +4719,30 @@ lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
        return 0;
 }
 
+/**
+ * lpfc_els_rcv_echo - Process an unsolicited echo iocb
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @cmdiocb: pointer to lpfc command iocb data structure.
+ * @ndlp: pointer to a node-list data structure.
+ *
+ * Return code
+ *   0 - Successfully processed echo iocb (currently always return 0)
+ **/
+static int
+lpfc_els_rcv_echo(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+                 struct lpfc_nodelist *ndlp)
+{
+       uint8_t *pcmd;
+
+       pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt);
+
+       /* skip over first word of echo command to find echo data */
+       pcmd += sizeof(uint32_t);
+
+       lpfc_els_rsp_echo_acc(vport, pcmd, cmdiocb, ndlp);
+       return 0;
+}
+
 /**
  * lpfc_els_rcv_lirr - Process an unsolicited lirr iocb
  * @vport: pointer to a host virtual N_Port data structure.
@@ -4734,6 +4794,89 @@ lpfc_els_rcv_rrq(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
        lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
 }
 
+/**
+ * lpfc_els_rsp_rls_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd
+ * @phba: pointer to lpfc hba data structure.
+ * @pmb: pointer to the driver internal queue element for mailbox command.
+ *
+ * This routine is the completion callback function for the MBX_READ_LNK_STAT
+ * mailbox command. This callback function is to actually send the Accept
+ * (ACC) response to a Read Port Status (RPS) unsolicited IOCB event. It
+ * collects the link statistics from the completion of the MBX_READ_LNK_STAT
+ * mailbox command, constructs the RPS response with the link statistics
+ * collected, and then invokes the lpfc_sli_issue_iocb() routine to send ACC
+ * response to the RPS.
+ *
+ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp
+ * will be incremented by 1 for holding the ndlp and the reference to ndlp
+ * will be stored into the context1 field of the IOCB for the completion
+ * callback function to the RPS Accept Response ELS IOCB command.
+ *
+ **/
+static void
+lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+       MAILBOX_t *mb;
+       IOCB_t *icmd;
+       struct RLS_RSP *rls_rsp;
+       uint8_t *pcmd;
+       struct lpfc_iocbq *elsiocb;
+       struct lpfc_nodelist *ndlp;
+       uint16_t xri;
+       uint32_t cmdsize;
+
+       mb = &pmb->u.mb;
+
+       ndlp = (struct lpfc_nodelist *) pmb->context2;
+       xri = (uint16_t) ((unsigned long)(pmb->context1));
+       pmb->context1 = NULL;
+       pmb->context2 = NULL;
+
+       if (mb->mbxStatus) {
+               mempool_free(pmb, phba->mbox_mem_pool);
+               return;
+       }
+
+       cmdsize = sizeof(struct RLS_RSP) + sizeof(uint32_t);
+       mempool_free(pmb, phba->mbox_mem_pool);
+       elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
+                                    lpfc_max_els_tries, ndlp,
+                                    ndlp->nlp_DID, ELS_CMD_ACC);
+
+       /* Decrement the ndlp reference count from previous mbox command */
+       lpfc_nlp_put(ndlp);
+
+       if (!elsiocb)
+               return;
+
+       icmd = &elsiocb->iocb;
+       icmd->ulpContext = xri;
+
+       pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+       *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
+       pcmd += sizeof(uint32_t); /* Skip past command */
+       rls_rsp = (struct RLS_RSP *)pcmd;
+
+       rls_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt);
+       rls_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt);
+       rls_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt);
+       rls_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt);
+       rls_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord);
+       rls_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt);
+
+       /* Xmit ELS RLS ACC response tag <ulpIoTag> */
+       lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
+                        "2874 Xmit ELS RLS ACC response tag x%x xri x%x, "
+                        "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+                        elsiocb->iotag, elsiocb->iocb.ulpContext,
+                        ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+                        ndlp->nlp_rpi);
+       elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
+       phba->fc_stat.elsXmitACC++;
+       if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR)
+               lpfc_els_free_iocb(phba, elsiocb);
+}
+
 /**
  * lpfc_els_rsp_rps_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd
  * @phba: pointer to lpfc hba data structure.
@@ -4827,7 +4970,155 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 }
 
 /**
- * lpfc_els_rcv_rps - Process an unsolicited rps iocb
+ * lpfc_els_rcv_rls - Process an unsolicited rls iocb
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @cmdiocb: pointer to lpfc command iocb data structure.
+ * @ndlp: pointer to a node-list data structure.
+ *
+ * This routine processes Read Port Status (RPL) IOCB received as an
+ * ELS unsolicited event. It first checks the remote port state. If the
+ * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE
+ * state, it invokes the lpfc_els_rsl_reject() routine to send the reject
+ * response. Otherwise, it issue the MBX_READ_LNK_STAT mailbox command
+ * for reading the HBA link statistics. It is for the callback function,
+ * lpfc_els_rsp_rls_acc(), set to the MBX_READ_LNK_STAT mailbox command
+ * to actually sending out RPL Accept (ACC) response.
+ *
+ * Return codes
+ *   0 - Successfully processed rls iocb (currently always return 0)
+ **/
+static int
+lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+                struct lpfc_nodelist *ndlp)
+{
+       struct lpfc_hba *phba = vport->phba;
+       LPFC_MBOXQ_t *mbox;
+       struct lpfc_dmabuf *pcmd;
+       struct ls_rjt stat;
+
+       if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
+           (ndlp->nlp_state != NLP_STE_MAPPED_NODE))
+               /* reject the unsolicited RPS request and done with it */
+               goto reject_out;
+
+       pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
+       if (mbox) {
+               lpfc_read_lnk_stat(phba, mbox);
+               mbox->context1 =
+                   (void *)((unsigned long) cmdiocb->iocb.ulpContext);
+               mbox->context2 = lpfc_nlp_get(ndlp);
+               mbox->vport = vport;
+               mbox->mbox_cmpl = lpfc_els_rsp_rls_acc;
+               if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
+                       != MBX_NOT_FINISHED)
+                       /* Mbox completion will send ELS Response */
+                       return 0;
+               /* Decrement reference count used for the failed mbox
+                * command.
+                */
+               lpfc_nlp_put(ndlp);
+               mempool_free(mbox, phba->mbox_mem_pool);
+       }
+reject_out:
+       /* issue rejection response */
+       stat.un.b.lsRjtRsvd0 = 0;
+       stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+       stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
+       stat.un.b.vendorUnique = 0;
+       lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
+       return 0;
+}
+
+/**
+ * lpfc_els_rcv_rtv - Process an unsolicited rtv iocb
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @cmdiocb: pointer to lpfc command iocb data structure.
+ * @ndlp: pointer to a node-list data structure.
+ *
+ * This routine processes Read Timout Value (RTV) IOCB received as an
+ * ELS unsolicited event. It first checks the remote port state. If the
+ * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE
+ * state, it invokes the lpfc_els_rsl_reject() routine to send the reject
+ * response. Otherwise, it sends the Accept(ACC) response to a Read Timeout
+ * Value (RTV) unsolicited IOCB event.
+ *
+ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp
+ * will be incremented by 1 for holding the ndlp and the reference to ndlp
+ * will be stored into the context1 field of the IOCB for the completion
+ * callback function to the RPS Accept Response ELS IOCB command.
+ *
+ * Return codes
+ *   0 - Successfully processed rtv iocb (currently always return 0)
+ **/
+static int
+lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+                struct lpfc_nodelist *ndlp)
+{
+       struct lpfc_hba *phba = vport->phba;
+       struct ls_rjt stat;
+       struct RTV_RSP *rtv_rsp;
+       uint8_t *pcmd;
+       struct lpfc_iocbq *elsiocb;
+       uint32_t cmdsize;
+
+
+       if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
+           (ndlp->nlp_state != NLP_STE_MAPPED_NODE))
+               /* reject the unsolicited RPS request and done with it */
+               goto reject_out;
+
+       cmdsize = sizeof(struct RTV_RSP) + sizeof(uint32_t);
+       elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
+                                    lpfc_max_els_tries, ndlp,
+                                    ndlp->nlp_DID, ELS_CMD_ACC);
+
+       if (!elsiocb)
+               return 1;
+
+       pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+               *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
+       pcmd += sizeof(uint32_t); /* Skip past command */
+
+       /* use the command's xri in the response */
+       elsiocb->iocb.ulpContext = cmdiocb->iocb.ulpContext;
+
+       rtv_rsp = (struct RTV_RSP *)pcmd;
+
+       /* populate RTV payload */
+       rtv_rsp->ratov = cpu_to_be32(phba->fc_ratov * 1000); /* report msecs */
+       rtv_rsp->edtov = cpu_to_be32(phba->fc_edtov);
+       bf_set(qtov_edtovres, rtv_rsp, phba->fc_edtovResol ? 1 : 0);
+       bf_set(qtov_rttov, rtv_rsp, 0); /* Field is for FC ONLY */
+       rtv_rsp->qtov = cpu_to_be32(rtv_rsp->qtov);
+
+       /* Xmit ELS RLS ACC response tag <ulpIoTag> */
+       lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
+                        "2875 Xmit ELS RTV ACC response tag x%x xri x%x, "
+                        "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x, "
+                        "Data: x%x x%x x%x\n",
+                        elsiocb->iotag, elsiocb->iocb.ulpContext,
+                        ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+                        ndlp->nlp_rpi,
+                       rtv_rsp->ratov, rtv_rsp->edtov, rtv_rsp->qtov);
+       elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
+       phba->fc_stat.elsXmitACC++;
+       if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR)
+               lpfc_els_free_iocb(phba, elsiocb);
+       return 0;
+
+reject_out:
+       /* issue rejection response */
+       stat.un.b.lsRjtRsvd0 = 0;
+       stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+       stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
+       stat.un.b.vendorUnique = 0;
+       lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
+       return 0;
+}
+
+/* lpfc_els_rcv_rps - Process an unsolicited rps iocb
  * @vport: pointer to a host virtual N_Port data structure.
  * @cmdiocb: pointer to lpfc command iocb data structure.
  * @ndlp: pointer to a node-list data structure.
@@ -5017,7 +5308,6 @@ lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
        pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
        lp = (uint32_t *) pcmd->virt;
        rpl = (RPL *) (lp + 1);
-
        maxsize = be32_to_cpu(rpl->maxsize);
 
        /* We support only one port */
@@ -5836,6 +6126,16 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                if (newnode)
                        lpfc_nlp_put(ndlp);
                break;
+       case ELS_CMD_RLS:
+               lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+                       "RCV RLS:         did:x%x/ste:x%x flg:x%x",
+                       did, vport->port_state, ndlp->nlp_flag);
+
+               phba->fc_stat.elsRcvRLS++;
+               lpfc_els_rcv_rls(vport, elsiocb, ndlp);
+               if (newnode)
+                       lpfc_nlp_put(ndlp);
+               break;
        case ELS_CMD_RPS:
                lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
                        "RCV RPS:         did:x%x/ste:x%x flg:x%x",
@@ -5866,6 +6166,15 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                if (newnode)
                        lpfc_nlp_put(ndlp);
                break;
+       case ELS_CMD_RTV:
+               lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+                       "RCV RTV:        did:x%x/ste:x%x flg:x%x",
+                       did, vport->port_state, ndlp->nlp_flag);
+               phba->fc_stat.elsRcvRTV++;
+               lpfc_els_rcv_rtv(vport, elsiocb, ndlp);
+               if (newnode)
+                       lpfc_nlp_put(ndlp);
+               break;
        case ELS_CMD_RRQ:
                lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
                        "RCV RRQ:         did:x%x/ste:x%x flg:x%x",
@@ -5876,6 +6185,16 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                if (newnode)
                        lpfc_nlp_put(ndlp);
                break;
+       case ELS_CMD_ECHO:
+               lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+                       "RCV ECHO:        did:x%x/ste:x%x flg:x%x",
+                       did, vport->port_state, ndlp->nlp_flag);
+
+               phba->fc_stat.elsRcvECHO++;
+               lpfc_els_rcv_echo(vport, elsiocb, ndlp);
+               if (newnode)
+                       lpfc_nlp_put(ndlp);
+               break;
        default:
                lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
                        "RCV ELS cmd:     cmd:x%x did:x%x/ste:x%x",
@@ -6170,6 +6489,8 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 
                default:
                        /* Try to recover from this error */
+                       if (phba->sli_rev == LPFC_SLI_REV4)
+                               lpfc_sli4_unreg_all_rpis(vport);
                        lpfc_mbx_unreg_vpi(vport);
                        spin_lock_irq(shost->host_lock);
                        vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
@@ -6437,6 +6758,10 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        lpfc_unreg_rpi(vport, np);
                }
                lpfc_cleanup_pending_mbox(vport);
+
+               if (phba->sli_rev == LPFC_SLI_REV4)
+                       lpfc_sli4_unreg_all_rpis(vport);
+
                lpfc_mbx_unreg_vpi(vport);
                spin_lock_irq(shost->host_lock);
                vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
@@ -6452,7 +6777,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                 * to update the MAC address.
                 */
                lpfc_register_new_vport(phba, vport, ndlp);
-               return ;
+               goto out;
        }
 
        if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI)
index a345dde16c86fcf74b121b38d2e505102b3ee698..a5d1695dac3dcd73b1e5cae6651c46c602d57d20 100644 (file)
@@ -20,6 +20,7 @@
  *******************************************************************/
 
 #include <linux/blkdev.h>
+#include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/kthread.h>
@@ -63,6 +64,7 @@ static uint8_t lpfcAlpaArray[] = {
 static void lpfc_disc_timeout_handler(struct lpfc_vport *);
 static void lpfc_disc_flush_list(struct lpfc_vport *vport);
 static void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
+static int lpfc_fcf_inuse(struct lpfc_hba *);
 
 void
 lpfc_terminate_rport_io(struct fc_rport *rport)
@@ -160,11 +162,17 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
        return;
 }
 
-/*
- * This function is called from the worker thread when dev_loss_tmo
- * expire.
- */
-static void
+/**
+ * lpfc_dev_loss_tmo_handler - Remote node devloss timeout handler
+ * @ndlp: Pointer to remote node object.
+ *
+ * This function is called from the worker thread when devloss timeout timer
+ * expires. For SLI4 host, this routine shall return 1 when at lease one
+ * remote node, including this @ndlp, is still in use of FCF; otherwise, this
+ * routine shall return 0 when there is no remote node is still in use of FCF
+ * when devloss timeout happened to this @ndlp.
+ **/
+static int
 lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
 {
        struct lpfc_rport_data *rdata;
@@ -175,17 +183,21 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
        int  put_node;
        int  put_rport;
        int warn_on = 0;
+       int fcf_inuse = 0;
 
        rport = ndlp->rport;
 
        if (!rport)
-               return;
+               return fcf_inuse;
 
        rdata = rport->dd_data;
        name = (uint8_t *) &ndlp->nlp_portname;
        vport = ndlp->vport;
        phba  = vport->phba;
 
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               fcf_inuse = lpfc_fcf_inuse(phba);
+
        lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
                "rport devlosstmo:did:x%x type:x%x id:x%x",
                ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id);
@@ -209,7 +221,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
                        lpfc_nlp_put(ndlp);
                if (put_rport)
                        put_device(&rport->dev);
-               return;
+               return fcf_inuse;
        }
 
        if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) {
@@ -220,7 +232,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
                                 *name, *(name+1), *(name+2), *(name+3),
                                 *(name+4), *(name+5), *(name+6), *(name+7),
                                 ndlp->nlp_DID);
-               return;
+               return fcf_inuse;
        }
 
        if (ndlp->nlp_type & NLP_FABRIC) {
@@ -233,7 +245,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
                        lpfc_nlp_put(ndlp);
                if (put_rport)
                        put_device(&rport->dev);
-               return;
+               return fcf_inuse;
        }
 
        if (ndlp->nlp_sid != NLP_NO_SID) {
@@ -280,6 +292,74 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
            (ndlp->nlp_state != NLP_STE_PRLI_ISSUE))
                lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
 
+       return fcf_inuse;
+}
+
+/**
+ * lpfc_sli4_post_dev_loss_tmo_handler - SLI4 post devloss timeout handler
+ * @phba: Pointer to hba context object.
+ * @fcf_inuse: SLI4 FCF in-use state reported from devloss timeout handler.
+ * @nlp_did: remote node identifer with devloss timeout.
+ *
+ * This function is called from the worker thread after invoking devloss
+ * timeout handler and releasing the reference count for the ndlp with
+ * which the devloss timeout was handled for SLI4 host. For the devloss
+ * timeout of the last remote node which had been in use of FCF, when this
+ * routine is invoked, it shall be guaranteed that none of the remote are
+ * in-use of FCF. When devloss timeout to the last remote using the FCF,
+ * if the FIP engine is neither in FCF table scan process nor roundrobin
+ * failover process, the in-use FCF shall be unregistered. If the FIP
+ * engine is in FCF discovery process, the devloss timeout state shall
+ * be set for either the FCF table scan process or roundrobin failover
+ * process to unregister the in-use FCF.
+ **/
+static void
+lpfc_sli4_post_dev_loss_tmo_handler(struct lpfc_hba *phba, int fcf_inuse,
+                                   uint32_t nlp_did)
+{
+       /* If devloss timeout happened to a remote node when FCF had no
+        * longer been in-use, do nothing.
+        */
+       if (!fcf_inuse)
+               return;
+
+       if ((phba->hba_flag & HBA_FIP_SUPPORT) && !lpfc_fcf_inuse(phba)) {
+               spin_lock_irq(&phba->hbalock);
+               if (phba->fcf.fcf_flag & FCF_DISCOVERY) {
+                       if (phba->hba_flag & HBA_DEVLOSS_TMO) {
+                               spin_unlock_irq(&phba->hbalock);
+                               return;
+                       }
+                       phba->hba_flag |= HBA_DEVLOSS_TMO;
+                       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                                       "2847 Last remote node (x%x) using "
+                                       "FCF devloss tmo\n", nlp_did);
+               }
+               if (phba->fcf.fcf_flag & FCF_REDISC_PROG) {
+                       spin_unlock_irq(&phba->hbalock);
+                       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                                       "2868 Devloss tmo to FCF rediscovery "
+                                       "in progress\n");
+                       return;
+               }
+               if (!(phba->hba_flag & (FCF_TS_INPROG | FCF_RR_INPROG))) {
+                       spin_unlock_irq(&phba->hbalock);
+                       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                                       "2869 Devloss tmo to idle FIP engine, "
+                                       "unreg in-use FCF and rescan.\n");
+                       /* Unregister in-use FCF and rescan */
+                       lpfc_unregister_fcf_rescan(phba);
+                       return;
+               }
+               spin_unlock_irq(&phba->hbalock);
+               if (phba->hba_flag & FCF_TS_INPROG)
+                       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                                       "2870 FCF table scan in progress\n");
+               if (phba->hba_flag & FCF_RR_INPROG)
+                       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                                       "2871 FLOGI roundrobin FCF failover "
+                                       "in progress\n");
+       }
        lpfc_unregister_unused_fcf(phba);
 }
 
@@ -408,6 +488,8 @@ lpfc_work_list_done(struct lpfc_hba *phba)
        struct lpfc_work_evt  *evtp = NULL;
        struct lpfc_nodelist  *ndlp;
        int free_evt;
+       int fcf_inuse;
+       uint32_t nlp_did;
 
        spin_lock_irq(&phba->hbalock);
        while (!list_empty(&phba->work_list)) {
@@ -427,12 +509,17 @@ lpfc_work_list_done(struct lpfc_hba *phba)
                        break;
                case LPFC_EVT_DEV_LOSS:
                        ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
-                       lpfc_dev_loss_tmo_handler(ndlp);
+                       fcf_inuse = lpfc_dev_loss_tmo_handler(ndlp);
                        free_evt = 0;
                        /* decrement the node reference count held for
                         * this queued work
                         */
+                       nlp_did = ndlp->nlp_DID;
                        lpfc_nlp_put(ndlp);
+                       if (phba->sli_rev == LPFC_SLI_REV4)
+                               lpfc_sli4_post_dev_loss_tmo_handler(phba,
+                                                                   fcf_inuse,
+                                                                   nlp_did);
                        break;
                case LPFC_EVT_ONLINE:
                        if (phba->link_state < LPFC_LINK_DOWN)
@@ -707,6 +794,8 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
                                             : NLP_EVT_DEVICE_RECOVERY);
        }
        if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) {
+               if (phba->sli_rev == LPFC_SLI_REV4)
+                       lpfc_sli4_unreg_all_rpis(vport);
                lpfc_mbx_unreg_vpi(vport);
                spin_lock_irq(shost->host_lock);
                vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
@@ -1021,8 +1110,7 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                         "2017 REG_FCFI mbxStatus error x%x "
                         "HBA state x%x\n",
                         mboxq->u.mb.mbxStatus, vport->port_state);
-               mempool_free(mboxq, phba->mbox_mem_pool);
-               return;
+               goto fail_out;
        }
 
        /* Start FCoE discovery by sending a FLOGI. */
@@ -1031,20 +1119,30 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
        spin_lock_irq(&phba->hbalock);
        phba->fcf.fcf_flag |= FCF_REGISTERED;
        spin_unlock_irq(&phba->hbalock);
+
        /* If there is a pending FCoE event, restart FCF table scan. */
-       if (lpfc_check_pending_fcoe_event(phba, 1)) {
-               mempool_free(mboxq, phba->mbox_mem_pool);
-               return;
-       }
+       if (lpfc_check_pending_fcoe_event(phba, LPFC_UNREG_FCF))
+               goto fail_out;
+
+       /* Mark successful completion of FCF table scan */
        spin_lock_irq(&phba->hbalock);
        phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE);
-       phba->hba_flag &= ~FCF_DISC_INPROGRESS;
-       spin_unlock_irq(&phba->hbalock);
-       if (vport->port_state != LPFC_FLOGI)
+       phba->hba_flag &= ~FCF_TS_INPROG;
+       if (vport->port_state != LPFC_FLOGI) {
+               phba->hba_flag |= FCF_RR_INPROG;
+               spin_unlock_irq(&phba->hbalock);
                lpfc_initial_flogi(vport);
+               goto out;
+       }
+       spin_unlock_irq(&phba->hbalock);
+       goto out;
 
+fail_out:
+       spin_lock_irq(&phba->hbalock);
+       phba->hba_flag &= ~FCF_RR_INPROG;
+       spin_unlock_irq(&phba->hbalock);
+out:
        mempool_free(mboxq, phba->mbox_mem_pool);
-       return;
 }
 
 /**
@@ -1241,10 +1339,9 @@ lpfc_register_fcf(struct lpfc_hba *phba)
        int rc;
 
        spin_lock_irq(&phba->hbalock);
-
        /* If the FCF is not availabe do nothing. */
        if (!(phba->fcf.fcf_flag & FCF_AVAILABLE)) {
-               phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+               phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG);
                spin_unlock_irq(&phba->hbalock);
                return;
        }
@@ -1252,19 +1349,22 @@ lpfc_register_fcf(struct lpfc_hba *phba)
        /* The FCF is already registered, start discovery */
        if (phba->fcf.fcf_flag & FCF_REGISTERED) {
                phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE);
-               phba->hba_flag &= ~FCF_DISC_INPROGRESS;
-               spin_unlock_irq(&phba->hbalock);
-               if (phba->pport->port_state != LPFC_FLOGI)
+               phba->hba_flag &= ~FCF_TS_INPROG;
+               if (phba->pport->port_state != LPFC_FLOGI) {
+                       phba->hba_flag |= FCF_RR_INPROG;
+                       spin_unlock_irq(&phba->hbalock);
                        lpfc_initial_flogi(phba->pport);
+                       return;
+               }
+               spin_unlock_irq(&phba->hbalock);
                return;
        }
        spin_unlock_irq(&phba->hbalock);
 
-       fcf_mbxq = mempool_alloc(phba->mbox_mem_pool,
-               GFP_KERNEL);
+       fcf_mbxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!fcf_mbxq) {
                spin_lock_irq(&phba->hbalock);
-               phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+               phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG);
                spin_unlock_irq(&phba->hbalock);
                return;
        }
@@ -1275,7 +1375,7 @@ lpfc_register_fcf(struct lpfc_hba *phba)
        rc = lpfc_sli_issue_mbox(phba, fcf_mbxq, MBX_NOWAIT);
        if (rc == MBX_NOT_FINISHED) {
                spin_lock_irq(&phba->hbalock);
-               phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+               phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG);
                spin_unlock_irq(&phba->hbalock);
                mempool_free(fcf_mbxq, phba->mbox_mem_pool);
        }
@@ -1493,7 +1593,7 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
         * FCF discovery, no need to restart FCF discovery.
         */
        if ((phba->link_state  >= LPFC_LINK_UP) &&
-               (phba->fcoe_eventtag == phba->fcoe_eventtag_at_fcf_scan))
+           (phba->fcoe_eventtag == phba->fcoe_eventtag_at_fcf_scan))
                return 0;
 
        lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
@@ -1517,14 +1617,14 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
                lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST);
        } else {
                /*
-                * Do not continue FCF discovery and clear FCF_DISC_INPROGRESS
+                * Do not continue FCF discovery and clear FCF_TS_INPROG
                 * flag
                 */
                lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
                                "2833 Stop FCF discovery process due to link "
                                "state change (x%x)\n", phba->link_state);
                spin_lock_irq(&phba->hbalock);
-               phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+               phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG);
                phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV | FCF_DISCOVERY);
                spin_unlock_irq(&phba->hbalock);
        }
@@ -1728,6 +1828,65 @@ lpfc_sli4_fcf_record_match(struct lpfc_hba *phba,
        return true;
 }
 
+/**
+ * lpfc_sli4_fcf_rr_next_proc - processing next roundrobin fcf
+ * @vport: Pointer to vport object.
+ * @fcf_index: index to next fcf.
+ *
+ * This function processing the roundrobin fcf failover to next fcf index.
+ * When this function is invoked, there will be a current fcf registered
+ * for flogi.
+ * Return: 0 for continue retrying flogi on currently registered fcf;
+ *         1 for stop flogi on currently registered fcf;
+ */
+int lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *vport, uint16_t fcf_index)
+{
+       struct lpfc_hba *phba = vport->phba;
+       int rc;
+
+       if (fcf_index == LPFC_FCOE_FCF_NEXT_NONE) {
+               spin_lock_irq(&phba->hbalock);
+               if (phba->hba_flag & HBA_DEVLOSS_TMO) {
+                       spin_unlock_irq(&phba->hbalock);
+                       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                                       "2872 Devloss tmo with no eligible "
+                                       "FCF, unregister in-use FCF (x%x) "
+                                       "and rescan FCF table\n",
+                                       phba->fcf.current_rec.fcf_indx);
+                       lpfc_unregister_fcf_rescan(phba);
+                       goto stop_flogi_current_fcf;
+               }
+               /* Mark the end to FLOGI roundrobin failover */
+               phba->hba_flag &= ~FCF_RR_INPROG;
+               /* Allow action to new fcf asynchronous event */
+               phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_SCAN_DONE);
+               spin_unlock_irq(&phba->hbalock);
+               lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                               "2865 No FCF available, stop roundrobin FCF "
+                               "failover and change port state:x%x/x%x\n",
+                               phba->pport->port_state, LPFC_VPORT_UNKNOWN);
+               phba->pport->port_state = LPFC_VPORT_UNKNOWN;
+               goto stop_flogi_current_fcf;
+       } else {
+               lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_ELS,
+                               "2794 Try FLOGI roundrobin FCF failover to "
+                               "(x%x)\n", fcf_index);
+               rc = lpfc_sli4_fcf_rr_read_fcf_rec(phba, fcf_index);
+               if (rc)
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS,
+                                       "2761 FLOGI roundrobin FCF failover "
+                                       "failed (rc:x%x) to read FCF (x%x)\n",
+                                       rc, phba->fcf.current_rec.fcf_indx);
+               else
+                       goto stop_flogi_current_fcf;
+       }
+       return 0;
+
+stop_flogi_current_fcf:
+       lpfc_can_disctmo(vport);
+       return 1;
+}
+
 /**
  * lpfc_mbx_cmpl_fcf_scan_read_fcf_rec - fcf scan read_fcf mbox cmpl handler.
  * @phba: pointer to lpfc hba data structure.
@@ -1756,7 +1915,7 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
        int rc;
 
        /* If there is pending FCoE event restart FCF table scan */
-       if (lpfc_check_pending_fcoe_event(phba, 0)) {
+       if (lpfc_check_pending_fcoe_event(phba, LPFC_SKIP_UNREG_FCF)) {
                lpfc_sli4_mbox_cmd_free(phba, mboxq);
                return;
        }
@@ -1765,12 +1924,12 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
        new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq,
                                                      &next_fcf_index);
        if (!new_fcf_record) {
-               lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
                                "2765 Mailbox command READ_FCF_RECORD "
                                "failed to retrieve a FCF record.\n");
                /* Let next new FCF event trigger fast failover */
                spin_lock_irq(&phba->hbalock);
-               phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+               phba->hba_flag &= ~FCF_TS_INPROG;
                spin_unlock_irq(&phba->hbalock);
                lpfc_sli4_mbox_cmd_free(phba, mboxq);
                return;
@@ -1787,13 +1946,12 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
        /*
         * If the fcf record does not match with connect list entries
         * read the next entry; otherwise, this is an eligible FCF
-        * record for round robin FCF failover.
+        * record for roundrobin FCF failover.
         */
        if (!rc) {
                lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
-                               "2781 FCF record (x%x) failed FCF "
-                               "connection list check, fcf_avail:x%x, "
-                               "fcf_valid:x%x\n",
+                               "2781 FCF (x%x) failed connection "
+                               "list check: (x%x/x%x)\n",
                                bf_get(lpfc_fcf_record_fcf_index,
                                       new_fcf_record),
                                bf_get(lpfc_fcf_record_fcf_avail,
@@ -1803,6 +1961,16 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                if ((phba->fcf.fcf_flag & FCF_IN_USE) &&
                    lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
                    new_fcf_record, LPFC_FCOE_IGNORE_VID)) {
+                       if (bf_get(lpfc_fcf_record_fcf_index, new_fcf_record) !=
+                           phba->fcf.current_rec.fcf_indx) {
+                               lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
+                                       "2862 FCF (x%x) matches property "
+                                       "of in-use FCF (x%x)\n",
+                                       bf_get(lpfc_fcf_record_fcf_index,
+                                              new_fcf_record),
+                                       phba->fcf.current_rec.fcf_indx);
+                               goto read_next_fcf;
+                       }
                        /*
                         * In case the current in-use FCF record becomes
                         * invalid/unavailable during FCF discovery that
@@ -1813,9 +1981,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                            !(phba->fcf.fcf_flag & FCF_REDISC_FOV)) {
                                lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
                                                "2835 Invalid in-use FCF "
-                                               "record (x%x) reported, "
-                                               "entering fast FCF failover "
-                                               "mode scanning.\n",
+                                               "(x%x), enter FCF failover "
+                                               "table scan.\n",
                                                phba->fcf.current_rec.fcf_indx);
                                spin_lock_irq(&phba->hbalock);
                                phba->fcf.fcf_flag |= FCF_REDISC_FOV;
@@ -1844,22 +2011,29 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
        if (phba->fcf.fcf_flag & FCF_IN_USE) {
                if (lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
                    new_fcf_record, vlan_id)) {
-                       phba->fcf.fcf_flag |= FCF_AVAILABLE;
-                       if (phba->fcf.fcf_flag & FCF_REDISC_PEND)
-                               /* Stop FCF redisc wait timer if pending */
-                               __lpfc_sli4_stop_fcf_redisc_wait_timer(phba);
-                       else if (phba->fcf.fcf_flag & FCF_REDISC_FOV)
-                               /* If in fast failover, mark it's completed */
-                               phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
-                       spin_unlock_irq(&phba->hbalock);
-                       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
-                                       "2836 The new FCF record (x%x) "
-                                       "matches the in-use FCF record "
-                                       "(x%x)\n",
-                                       phba->fcf.current_rec.fcf_indx,
+                       if (bf_get(lpfc_fcf_record_fcf_index, new_fcf_record) ==
+                           phba->fcf.current_rec.fcf_indx) {
+                               phba->fcf.fcf_flag |= FCF_AVAILABLE;
+                               if (phba->fcf.fcf_flag & FCF_REDISC_PEND)
+                                       /* Stop FCF redisc wait timer */
+                                       __lpfc_sli4_stop_fcf_redisc_wait_timer(
+                                                                       phba);
+                               else if (phba->fcf.fcf_flag & FCF_REDISC_FOV)
+                                       /* Fast failover, mark completed */
+                                       phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
+                               spin_unlock_irq(&phba->hbalock);
+                               lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                                               "2836 New FCF matches in-use "
+                                               "FCF (x%x)\n",
+                                               phba->fcf.current_rec.fcf_indx);
+                               goto out;
+                       } else
+                               lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
+                                       "2863 New FCF (x%x) matches "
+                                       "property of in-use FCF (x%x)\n",
                                        bf_get(lpfc_fcf_record_fcf_index,
-                                              new_fcf_record));
-                       goto out;
+                                              new_fcf_record),
+                                       phba->fcf.current_rec.fcf_indx);
                }
                /*
                 * Read next FCF record from HBA searching for the matching
@@ -1953,8 +2127,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
         */
        if (fcf_rec) {
                lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
-                               "2840 Update current FCF record "
-                               "with initial FCF record (x%x)\n",
+                               "2840 Update initial FCF candidate "
+                               "with FCF (x%x)\n",
                                bf_get(lpfc_fcf_record_fcf_index,
                                       new_fcf_record));
                __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
@@ -1984,20 +2158,28 @@ read_next_fcf:
                         */
                        if (!(phba->fcf.failover_rec.flag & RECORD_VALID)) {
                                lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
-                                              "2782 No suitable FCF record "
-                                              "found during this round of "
-                                              "post FCF rediscovery scan: "
-                                              "fcf_evt_tag:x%x, fcf_index: "
-                                              "x%x\n",
+                                              "2782 No suitable FCF found: "
+                                              "(x%x/x%x)\n",
                                               phba->fcoe_eventtag_at_fcf_scan,
                                               bf_get(lpfc_fcf_record_fcf_index,
                                                      new_fcf_record));
+                               spin_lock_irq(&phba->hbalock);
+                               if (phba->hba_flag & HBA_DEVLOSS_TMO) {
+                                       phba->hba_flag &= ~FCF_TS_INPROG;
+                                       spin_unlock_irq(&phba->hbalock);
+                                       /* Unregister in-use FCF and rescan */
+                                       lpfc_printf_log(phba, KERN_INFO,
+                                                       LOG_FIP,
+                                                       "2864 On devloss tmo "
+                                                       "unreg in-use FCF and "
+                                                       "rescan FCF table\n");
+                                       lpfc_unregister_fcf_rescan(phba);
+                                       return;
+                               }
                                /*
-                                * Let next new FCF event trigger fast
-                                * failover
+                                * Let next new FCF event trigger fast failover
                                 */
-                               spin_lock_irq(&phba->hbalock);
-                               phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+                               phba->hba_flag &= ~FCF_TS_INPROG;
                                spin_unlock_irq(&phba->hbalock);
                                return;
                        }
@@ -2015,9 +2197,8 @@ read_next_fcf:
 
                        /* Replace in-use record with the new record */
                        lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
-                                       "2842 Replace the current in-use "
-                                       "FCF record (x%x) with failover FCF "
-                                       "record (x%x)\n",
+                                       "2842 Replace in-use FCF (x%x) "
+                                       "with failover FCF (x%x)\n",
                                        phba->fcf.current_rec.fcf_indx,
                                        phba->fcf.failover_rec.fcf_indx);
                        memcpy(&phba->fcf.current_rec,
@@ -2029,15 +2210,8 @@ read_next_fcf:
                         * FCF failover.
                         */
                        spin_lock_irq(&phba->hbalock);
-                       phba->fcf.fcf_flag &=
-                                       ~(FCF_REDISC_FOV | FCF_REDISC_RRU);
+                       phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
                        spin_unlock_irq(&phba->hbalock);
-                       /*
-                        * Set up the initial registered FCF index for FLOGI
-                        * round robin FCF failover.
-                        */
-                       phba->fcf.fcf_rr_init_indx =
-                                       phba->fcf.failover_rec.fcf_indx;
                        /* Register to the new FCF record */
                        lpfc_register_fcf(phba);
                } else {
@@ -2069,28 +2243,6 @@ read_next_fcf:
                                                LPFC_FCOE_FCF_GET_FIRST);
                                return;
                        }
-
-                       /*
-                        * Otherwise, initial scan or post linkdown rescan,
-                        * register with the best FCF record found so far
-                        * through the FCF scanning process.
-                        */
-
-                       /*
-                        * Mark the initial FCF discovery completed and
-                        * the start of the first round of the roundrobin
-                        * FCF failover.
-                        */
-                       spin_lock_irq(&phba->hbalock);
-                       phba->fcf.fcf_flag &=
-                                       ~(FCF_INIT_DISC | FCF_REDISC_RRU);
-                       spin_unlock_irq(&phba->hbalock);
-                       /*
-                        * Set up the initial registered FCF index for FLOGI
-                        * round robin FCF failover
-                        */
-                       phba->fcf.fcf_rr_init_indx =
-                                       phba->fcf.current_rec.fcf_indx;
                        /* Register to the new FCF record */
                        lpfc_register_fcf(phba);
                }
@@ -2106,11 +2258,11 @@ out:
 }
 
 /**
- * lpfc_mbx_cmpl_fcf_rr_read_fcf_rec - fcf round robin read_fcf mbox cmpl hdler
+ * lpfc_mbx_cmpl_fcf_rr_read_fcf_rec - fcf roundrobin read_fcf mbox cmpl hdler
  * @phba: pointer to lpfc hba data structure.
  * @mboxq: pointer to mailbox object.
  *
- * This is the callback function for FLOGI failure round robin FCF failover
+ * This is the callback function for FLOGI failure roundrobin FCF failover
  * read FCF record mailbox command from the eligible FCF record bmask for
  * performing the failover. If the FCF read back is not valid/available, it
  * fails through to retrying FLOGI to the currently registered FCF again.
@@ -2125,17 +2277,18 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 {
        struct fcf_record *new_fcf_record;
        uint32_t boot_flag, addr_mode;
-       uint16_t next_fcf_index;
+       uint16_t next_fcf_index, fcf_index;
        uint16_t current_fcf_index;
        uint16_t vlan_id;
+       int rc;
 
-       /* If link state is not up, stop the round robin failover process */
+       /* If link state is not up, stop the roundrobin failover process */
        if (phba->link_state < LPFC_LINK_UP) {
                spin_lock_irq(&phba->hbalock);
                phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+               phba->hba_flag &= ~FCF_RR_INPROG;
                spin_unlock_irq(&phba->hbalock);
-               lpfc_sli4_mbox_cmd_free(phba, mboxq);
-               return;
+               goto out;
        }
 
        /* Parse the FCF record from the non-embedded mailbox command */
@@ -2145,23 +2298,47 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
                                "2766 Mailbox command READ_FCF_RECORD "
                                "failed to retrieve a FCF record.\n");
-               goto out;
+               goto error_out;
        }
 
        /* Get the needed parameters from FCF record */
-       lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag,
-                                &addr_mode, &vlan_id);
+       rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag,
+                                     &addr_mode, &vlan_id);
 
        /* Log the FCF record information if turned on */
        lpfc_sli4_log_fcf_record_info(phba, new_fcf_record, vlan_id,
                                      next_fcf_index);
 
+       fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
+       if (!rc) {
+               lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                               "2848 Remove ineligible FCF (x%x) from "
+                               "from roundrobin bmask\n", fcf_index);
+               /* Clear roundrobin bmask bit for ineligible FCF */
+               lpfc_sli4_fcf_rr_index_clear(phba, fcf_index);
+               /* Perform next round of roundrobin FCF failover */
+               fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba);
+               rc = lpfc_sli4_fcf_rr_next_proc(phba->pport, fcf_index);
+               if (rc)
+                       goto out;
+               goto error_out;
+       }
+
+       if (fcf_index == phba->fcf.current_rec.fcf_indx) {
+               lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                               "2760 Perform FLOGI roundrobin FCF failover: "
+                               "FCF (x%x) back to FCF (x%x)\n",
+                               phba->fcf.current_rec.fcf_indx, fcf_index);
+               /* Wait 500 ms before retrying FLOGI to current FCF */
+               msleep(500);
+               lpfc_initial_flogi(phba->pport);
+               goto out;
+       }
+
        /* Upload new FCF record to the failover FCF record */
        lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
-                       "2834 Update the current FCF record (x%x) "
-                       "with the next FCF record (x%x)\n",
-                       phba->fcf.failover_rec.fcf_indx,
-                       bf_get(lpfc_fcf_record_fcf_index, new_fcf_record));
+                       "2834 Update current FCF (x%x) with new FCF (x%x)\n",
+                       phba->fcf.failover_rec.fcf_indx, fcf_index);
        spin_lock_irq(&phba->hbalock);
        __lpfc_update_fcf_record(phba, &phba->fcf.failover_rec,
                                 new_fcf_record, addr_mode, vlan_id,
@@ -2178,14 +2355,13 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
               sizeof(struct lpfc_fcf_rec));
 
        lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
-                       "2783 FLOGI round robin FCF failover from FCF "
-                       "(x%x) to FCF (x%x).\n",
-                       current_fcf_index,
-                       bf_get(lpfc_fcf_record_fcf_index, new_fcf_record));
+                       "2783 Perform FLOGI roundrobin FCF failover: FCF "
+                       "(x%x) to FCF (x%x)\n", current_fcf_index, fcf_index);
 
+error_out:
+       lpfc_register_fcf(phba);
 out:
        lpfc_sli4_mbox_cmd_free(phba, mboxq);
-       lpfc_register_fcf(phba);
 }
 
 /**
@@ -2194,10 +2370,10 @@ out:
  * @mboxq: pointer to mailbox object.
  *
  * This is the callback function of read FCF record mailbox command for
- * updating the eligible FCF bmask for FLOGI failure round robin FCF
+ * updating the eligible FCF bmask for FLOGI failure roundrobin FCF
  * failover when a new FCF event happened. If the FCF read back is
  * valid/available and it passes the connection list check, it updates
- * the bmask for the eligible FCF record for round robin failover.
+ * the bmask for the eligible FCF record for roundrobin failover.
  */
 void
 lpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
@@ -2639,7 +2815,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
                 * and get the FCF Table.
                 */
                spin_lock_irq(&phba->hbalock);
-               if (phba->hba_flag & FCF_DISC_INPROGRESS) {
+               if (phba->hba_flag & FCF_TS_INPROG) {
                        spin_unlock_irq(&phba->hbalock);
                        return;
                }
@@ -3906,6 +4082,11 @@ lpfc_unreg_all_rpis(struct lpfc_vport *vport)
        LPFC_MBOXQ_t     *mbox;
        int rc;
 
+       if (phba->sli_rev == LPFC_SLI_REV4) {
+               lpfc_sli4_unreg_all_rpis(vport);
+               return;
+       }
+
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (mbox) {
                lpfc_unreg_login(phba, vport->vpi, 0xffff, mbox);
@@ -3992,6 +4173,16 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
        }
 
        spin_lock_irq(&phba->hbalock);
+       /* Cleanup REG_LOGIN completions which are not yet processed */
+       list_for_each_entry(mb, &phba->sli.mboxq_cmpl, list) {
+               if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) ||
+                       (ndlp != (struct lpfc_nodelist *) mb->context2))
+                       continue;
+
+               mb->context2 = NULL;
+               mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+       }
+
        list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
                if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
                    (ndlp == (struct lpfc_nodelist *) mb->context2)) {
@@ -5170,6 +5361,8 @@ lpfc_unregister_fcf_prep(struct lpfc_hba *phba)
                        if (ndlp)
                                lpfc_cancel_retry_delay_tmo(vports[i], ndlp);
                        lpfc_cleanup_pending_mbox(vports[i]);
+                       if (phba->sli_rev == LPFC_SLI_REV4)
+                               lpfc_sli4_unreg_all_rpis(vports[i]);
                        lpfc_mbx_unreg_vpi(vports[i]);
                        shost = lpfc_shost_from_vport(vports[i]);
                        spin_lock_irq(shost->host_lock);
index a631647051d99dc3cb53226ffd7602efe2cbfd19..9b833345646525c52b736f4f388e18f3f18695c4 100644 (file)
@@ -861,6 +861,47 @@ typedef struct  _RPS_RSP { /* Structure is in Big Endian format */
        uint32_t crcCnt;
 } RPS_RSP;
 
+struct RLS {                   /* Structure is in Big Endian format */
+       uint32_t rls;
+#define rls_rsvd_SHIFT         24
+#define rls_rsvd_MASK          0x000000ff
+#define rls_rsvd_WORD          rls
+#define rls_did_SHIFT          0
+#define rls_did_MASK           0x00ffffff
+#define rls_did_WORD           rls
+};
+
+struct  RLS_RSP {              /* Structure is in Big Endian format */
+       uint32_t linkFailureCnt;
+       uint32_t lossSyncCnt;
+       uint32_t lossSignalCnt;
+       uint32_t primSeqErrCnt;
+       uint32_t invalidXmitWord;
+       uint32_t crcCnt;
+};
+
+struct RTV_RSP {               /* Structure is in Big Endian format */
+       uint32_t ratov;
+       uint32_t edtov;
+       uint32_t qtov;
+#define qtov_rsvd0_SHIFT       28
+#define qtov_rsvd0_MASK                0x0000000f
+#define qtov_rsvd0_WORD                qtov            /* reserved */
+#define qtov_edtovres_SHIFT    27
+#define qtov_edtovres_MASK     0x00000001
+#define qtov_edtovres_WORD     qtov            /* E_D_TOV Resolution */
+#define qtov__rsvd1_SHIFT      19
+#define qtov_rsvd1_MASK                0x0000003f
+#define qtov_rsvd1_WORD                qtov            /* reserved */
+#define qtov_rttov_SHIFT       18
+#define qtov_rttov_MASK                0x00000001
+#define qtov_rttov_WORD                qtov            /* R_T_TOV value */
+#define qtov_rsvd2_SHIFT       0
+#define qtov_rsvd2_MASK                0x0003ffff
+#define qtov_rsvd2_WORD                qtov            /* reserved */
+};
+
+
 typedef struct  _RPL {         /* Structure is in Big Endian format */
        uint32_t maxsize;
        uint32_t index;
index bbdcf96800f619e952bdcb64df043bf789caf68e..6e4bc34e1d0d30028f2aaae15e615f5a0d067cd5 100644 (file)
@@ -424,79 +424,6 @@ struct lpfc_rcqe {
 #define FCOE_SOFn3     0x36
 };
 
-struct lpfc_wqe_generic{
-       struct ulp_bde64 bde;
-       uint32_t word3;
-       uint32_t word4;
-       uint32_t word5;
-       uint32_t word6;
-#define lpfc_wqe_gen_context_SHIFT     16
-#define lpfc_wqe_gen_context_MASK      0x0000FFFF
-#define lpfc_wqe_gen_context_WORD      word6
-#define lpfc_wqe_gen_xri_SHIFT         0
-#define lpfc_wqe_gen_xri_MASK          0x0000FFFF
-#define lpfc_wqe_gen_xri_WORD          word6
-       uint32_t word7;
-#define lpfc_wqe_gen_lnk_SHIFT         23
-#define lpfc_wqe_gen_lnk_MASK          0x00000001
-#define lpfc_wqe_gen_lnk_WORD          word7
-#define lpfc_wqe_gen_erp_SHIFT         22
-#define lpfc_wqe_gen_erp_MASK          0x00000001
-#define lpfc_wqe_gen_erp_WORD          word7
-#define lpfc_wqe_gen_pu_SHIFT          20
-#define lpfc_wqe_gen_pu_MASK           0x00000003
-#define lpfc_wqe_gen_pu_WORD           word7
-#define lpfc_wqe_gen_class_SHIFT       16
-#define lpfc_wqe_gen_class_MASK                0x00000007
-#define lpfc_wqe_gen_class_WORD                word7
-#define lpfc_wqe_gen_command_SHIFT     8
-#define lpfc_wqe_gen_command_MASK      0x000000FF
-#define lpfc_wqe_gen_command_WORD      word7
-#define lpfc_wqe_gen_status_SHIFT      4
-#define lpfc_wqe_gen_status_MASK       0x0000000F
-#define lpfc_wqe_gen_status_WORD       word7
-#define lpfc_wqe_gen_ct_SHIFT          2
-#define lpfc_wqe_gen_ct_MASK           0x00000003
-#define lpfc_wqe_gen_ct_WORD           word7
-       uint32_t abort_tag;
-       uint32_t word9;
-#define lpfc_wqe_gen_request_tag_SHIFT 0
-#define lpfc_wqe_gen_request_tag_MASK  0x0000FFFF
-#define lpfc_wqe_gen_request_tag_WORD  word9
-       uint32_t word10;
-#define lpfc_wqe_gen_ccp_SHIFT         24
-#define lpfc_wqe_gen_ccp_MASK          0x000000FF
-#define lpfc_wqe_gen_ccp_WORD          word10
-#define lpfc_wqe_gen_ccpe_SHIFT                23
-#define lpfc_wqe_gen_ccpe_MASK         0x00000001
-#define lpfc_wqe_gen_ccpe_WORD         word10
-#define lpfc_wqe_gen_pv_SHIFT          19
-#define lpfc_wqe_gen_pv_MASK           0x00000001
-#define lpfc_wqe_gen_pv_WORD           word10
-#define lpfc_wqe_gen_pri_SHIFT         16
-#define lpfc_wqe_gen_pri_MASK          0x00000007
-#define lpfc_wqe_gen_pri_WORD          word10
-       uint32_t word11;
-#define lpfc_wqe_gen_cq_id_SHIFT       16
-#define lpfc_wqe_gen_cq_id_MASK                0x0000FFFF
-#define lpfc_wqe_gen_cq_id_WORD                word11
-#define LPFC_WQE_CQ_ID_DEFAULT 0xffff
-#define lpfc_wqe_gen_wqec_SHIFT                7
-#define lpfc_wqe_gen_wqec_MASK         0x00000001
-#define lpfc_wqe_gen_wqec_WORD         word11
-#define ELS_ID_FLOGI 3
-#define ELS_ID_FDISC 2
-#define ELS_ID_LOGO  1
-#define ELS_ID_DEFAULT 0
-#define lpfc_wqe_gen_els_id_SHIFT      4
-#define lpfc_wqe_gen_els_id_MASK       0x00000003
-#define lpfc_wqe_gen_els_id_WORD       word11
-#define lpfc_wqe_gen_cmd_type_SHIFT    0
-#define lpfc_wqe_gen_cmd_type_MASK     0x0000000F
-#define lpfc_wqe_gen_cmd_type_WORD     word11
-       uint32_t payload[4];
-};
-
 struct lpfc_rqe {
        uint32_t address_hi;
        uint32_t address_lo;
@@ -2279,9 +2206,36 @@ struct wqe_common {
 #define wqe_reqtag_MASK       0x0000FFFF
 #define wqe_reqtag_WORD       word9
 #define wqe_rcvoxid_SHIFT     16
-#define wqe_rcvoxid_MASK       0x0000FFFF
-#define wqe_rcvoxid_WORD       word9
+#define wqe_rcvoxid_MASK      0x0000FFFF
+#define wqe_rcvoxid_WORD      word9
        uint32_t word10;
+#define wqe_ebde_cnt_SHIFT    0
+#define wqe_ebde_cnt_MASK     0x00000007
+#define wqe_ebde_cnt_WORD     word10
+#define wqe_lenloc_SHIFT      7
+#define wqe_lenloc_MASK       0x00000003
+#define wqe_lenloc_WORD       word10
+#define LPFC_WQE_LENLOC_NONE           0
+#define LPFC_WQE_LENLOC_WORD3  1
+#define LPFC_WQE_LENLOC_WORD12 2
+#define LPFC_WQE_LENLOC_WORD4  3
+#define wqe_qosd_SHIFT        9
+#define wqe_qosd_MASK         0x00000001
+#define wqe_qosd_WORD         word10
+#define wqe_xbl_SHIFT         11
+#define wqe_xbl_MASK          0x00000001
+#define wqe_xbl_WORD          word10
+#define wqe_iod_SHIFT         13
+#define wqe_iod_MASK          0x00000001
+#define wqe_iod_WORD          word10
+#define LPFC_WQE_IOD_WRITE     0
+#define LPFC_WQE_IOD_READ      1
+#define wqe_dbde_SHIFT        14
+#define wqe_dbde_MASK         0x00000001
+#define wqe_dbde_WORD         word10
+#define wqe_wqes_SHIFT        15
+#define wqe_wqes_MASK         0x00000001
+#define wqe_wqes_WORD         word10
 #define wqe_pri_SHIFT         16
 #define wqe_pri_MASK          0x00000007
 #define wqe_pri_WORD          word10
@@ -2295,18 +2249,26 @@ struct wqe_common {
 #define wqe_ccpe_MASK         0x00000001
 #define wqe_ccpe_WORD         word10
 #define wqe_ccp_SHIFT         24
-#define wqe_ccp_MASK         0x000000ff
-#define wqe_ccp_WORD         word10
+#define wqe_ccp_MASK          0x000000ff
+#define wqe_ccp_WORD          word10
        uint32_t word11;
-#define wqe_cmd_type_SHIFT  0
-#define wqe_cmd_type_MASK   0x0000000f
-#define wqe_cmd_type_WORD   word11
-#define wqe_wqec_SHIFT      7
-#define wqe_wqec_MASK       0x00000001
-#define wqe_wqec_WORD       word11
-#define wqe_cqid_SHIFT      16
-#define wqe_cqid_MASK       0x0000ffff
-#define wqe_cqid_WORD       word11
+#define wqe_cmd_type_SHIFT    0
+#define wqe_cmd_type_MASK     0x0000000f
+#define wqe_cmd_type_WORD     word11
+#define wqe_els_id_SHIFT      4
+#define wqe_els_id_MASK       0x00000003
+#define wqe_els_id_WORD       word11
+#define LPFC_ELS_ID_FLOGI      3
+#define LPFC_ELS_ID_FDISC      2
+#define LPFC_ELS_ID_LOGO       1
+#define LPFC_ELS_ID_DEFAULT    0
+#define wqe_wqec_SHIFT        7
+#define wqe_wqec_MASK         0x00000001
+#define wqe_wqec_WORD         word11
+#define wqe_cqid_SHIFT        16
+#define wqe_cqid_MASK         0x0000ffff
+#define wqe_cqid_WORD         word11
+#define LPFC_WQE_CQ_ID_DEFAULT 0xffff
 };
 
 struct wqe_did {
@@ -2325,6 +2287,15 @@ struct wqe_did {
 #define wqe_xmit_bls_xo_WORD          word5
 };
 
+struct lpfc_wqe_generic{
+       struct ulp_bde64 bde;
+       uint32_t word3;
+       uint32_t word4;
+       uint32_t word5;
+       struct wqe_common wqe_com;
+       uint32_t payload[4];
+};
+
 struct els_request64_wqe {
        struct ulp_bde64 bde;
        uint32_t payload_len;
@@ -2356,9 +2327,9 @@ struct els_request64_wqe {
 
 struct xmit_els_rsp64_wqe {
        struct ulp_bde64 bde;
-       uint32_t rsvd3;
+       uint32_t response_payload_len;
        uint32_t rsvd4;
-       struct wqe_did  wqe_dest;
+       struct wqe_did wqe_dest;
        struct wqe_common wqe_com; /* words 6-11 */
        uint32_t rsvd_12_15[4];
 };
@@ -2427,7 +2398,7 @@ struct wqe_rctl_dfctl {
 
 struct xmit_seq64_wqe {
        struct ulp_bde64 bde;
-       uint32_t paylaod_offset;
+       uint32_t rsvd3;
        uint32_t relative_offset;
        struct wqe_rctl_dfctl wge_ctl;
        struct wqe_common wqe_com; /* words 6-11 */
@@ -2437,7 +2408,7 @@ struct xmit_seq64_wqe {
 };
 struct xmit_bcast64_wqe {
        struct ulp_bde64 bde;
-       uint32_t paylaod_len;
+       uint32_t seq_payload_len;
        uint32_t rsvd4;
        struct wqe_rctl_dfctl wge_ctl; /* word 5 */
        struct wqe_common wqe_com;     /* words 6-11 */
@@ -2446,8 +2417,8 @@ struct xmit_bcast64_wqe {
 
 struct gen_req64_wqe {
        struct ulp_bde64 bde;
-       uint32_t command_len;
-       uint32_t payload_len;
+       uint32_t request_payload_len;
+       uint32_t relative_offset;
        struct wqe_rctl_dfctl wge_ctl; /* word 5 */
        struct wqe_common wqe_com;     /* words 6-11 */
        uint32_t rsvd_12_15[4];
@@ -2480,7 +2451,7 @@ struct abort_cmd_wqe {
 
 struct fcp_iwrite64_wqe {
        struct ulp_bde64 bde;
-       uint32_t payload_len;
+       uint32_t payload_offset_len;
        uint32_t total_xfer_len;
        uint32_t initial_xfer_len;
        struct wqe_common wqe_com;     /* words 6-11 */
@@ -2489,7 +2460,7 @@ struct fcp_iwrite64_wqe {
 
 struct fcp_iread64_wqe {
        struct ulp_bde64 bde;
-       uint32_t payload_len;          /* word 3 */
+       uint32_t payload_offset_len;   /* word 3 */
        uint32_t total_xfer_len;       /* word 4 */
        uint32_t rsrvd5;               /* word 5 */
        struct wqe_common wqe_com;     /* words 6-11 */
@@ -2497,10 +2468,12 @@ struct fcp_iread64_wqe {
 };
 
 struct fcp_icmnd64_wqe {
-       struct ulp_bde64 bde;    /* words 0-2 */
-       uint32_t rsrvd[3];             /* words 3-5 */
+       struct ulp_bde64 bde;          /* words 0-2 */
+       uint32_t rsrvd3;               /* word 3 */
+       uint32_t rsrvd4;               /* word 4 */
+       uint32_t rsrvd5;               /* word 5 */
        struct wqe_common wqe_com;     /* words 6-11 */
-       uint32_t rsvd_12_15[4];         /* word 12-15 */
+       uint32_t rsvd_12_15[4];        /* word 12-15 */
 };
 
 
index 295c7ddb36c11fa72eaa6626aa7203ac4fb1eabf..b3065791f30333b9667dcb0f9d3d222facb76fc0 100644 (file)
@@ -813,6 +813,7 @@ lpfc_hba_down_post_s3(struct lpfc_hba *phba)
 
        return 0;
 }
+
 /**
  * lpfc_hba_down_post_s4 - Perform lpfc uninitialization after HBA reset
  * @phba: pointer to lpfc HBA data structure.
@@ -2234,10 +2235,9 @@ lpfc_stop_vport_timers(struct lpfc_vport *vport)
 void
 __lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *phba)
 {
-       /* Clear pending FCF rediscovery wait and failover in progress flags */
-       phba->fcf.fcf_flag &= ~(FCF_REDISC_PEND |
-                               FCF_DEAD_DISC |
-                               FCF_ACVL_DISC);
+       /* Clear pending FCF rediscovery wait flag */
+       phba->fcf.fcf_flag &= ~FCF_REDISC_PEND;
+
        /* Now, try to stop the timer */
        del_timer(&phba->fcf.redisc_wait);
 }
@@ -2261,6 +2261,8 @@ lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *phba)
                return;
        }
        __lpfc_sli4_stop_fcf_redisc_wait_timer(phba);
+       /* Clear failover in progress flags */
+       phba->fcf.fcf_flag &= ~(FCF_DEAD_DISC | FCF_ACVL_DISC);
        spin_unlock_irq(&phba->hbalock);
 }
 
@@ -2935,8 +2937,7 @@ lpfc_sli4_fcf_redisc_wait_tmo(unsigned long ptr)
        phba->fcf.fcf_flag |= FCF_REDISC_EVT;
        spin_unlock_irq(&phba->hbalock);
        lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
-                       "2776 FCF rediscover wait timer expired, post "
-                       "a worker thread event for FCF table scan\n");
+                       "2776 FCF rediscover quiescent timer expired\n");
        /* wake up worker thread */
        lpfc_worker_wake_up(phba);
 }
@@ -3311,35 +3312,34 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
                if (event_type == LPFC_FCOE_EVENT_TYPE_NEW_FCF)
                        lpfc_printf_log(phba, KERN_ERR, LOG_FIP |
                                        LOG_DISCOVERY,
-                                       "2546 New FCF found event: "
-                                       "evt_tag:x%x, fcf_index:x%x\n",
+                                       "2546 New FCF event, evt_tag:x%x, "
+                                       "index:x%x\n",
                                        acqe_fcoe->event_tag,
                                        acqe_fcoe->index);
                else
                        lpfc_printf_log(phba, KERN_WARNING, LOG_FIP |
                                        LOG_DISCOVERY,
-                                       "2788 FCF parameter modified event: "
-                                       "evt_tag:x%x, fcf_index:x%x\n",
+                                       "2788 FCF param modified event, "
+                                       "evt_tag:x%x, index:x%x\n",
                                        acqe_fcoe->event_tag,
                                        acqe_fcoe->index);
                if (phba->fcf.fcf_flag & FCF_DISCOVERY) {
                        /*
                         * During period of FCF discovery, read the FCF
                         * table record indexed by the event to update
-                        * FCF round robin failover eligible FCF bmask.
+                        * FCF roundrobin failover eligible FCF bmask.
                         */
                        lpfc_printf_log(phba, KERN_INFO, LOG_FIP |
                                        LOG_DISCOVERY,
-                                       "2779 Read new FCF record with "
-                                       "fcf_index:x%x for updating FCF "
-                                       "round robin failover bmask\n",
+                                       "2779 Read FCF (x%x) for updating "
+                                       "roundrobin FCF failover bmask\n",
                                        acqe_fcoe->index);
                        rc = lpfc_sli4_read_fcf_rec(phba, acqe_fcoe->index);
                }
 
                /* If the FCF discovery is in progress, do nothing. */
                spin_lock_irq(&phba->hbalock);
-               if (phba->hba_flag & FCF_DISC_INPROGRESS) {
+               if (phba->hba_flag & FCF_TS_INPROG) {
                        spin_unlock_irq(&phba->hbalock);
                        break;
                }
@@ -3358,15 +3358,15 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
 
                /* Otherwise, scan the entire FCF table and re-discover SAN */
                lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
-                               "2770 Start FCF table scan due to new FCF "
-                               "event: evt_tag:x%x, fcf_index:x%x\n",
+                               "2770 Start FCF table scan per async FCF "
+                               "event, evt_tag:x%x, index:x%x\n",
                                acqe_fcoe->event_tag, acqe_fcoe->index);
                rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba,
                                                     LPFC_FCOE_FCF_GET_FIRST);
                if (rc)
                        lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
                                        "2547 Issue FCF scan read FCF mailbox "
-                                       "command failed 0x%x\n", rc);
+                                       "command failed (x%x)\n", rc);
                break;
 
        case LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL:
@@ -3378,9 +3378,8 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
 
        case LPFC_FCOE_EVENT_TYPE_FCF_DEAD:
                lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
-                       "2549 FCF disconnected from network index 0x%x"
-                       " tag 0x%x\n", acqe_fcoe->index,
-                       acqe_fcoe->event_tag);
+                       "2549 FCF (x%x) disconnected from network, "
+                       "tag:x%x\n", acqe_fcoe->index, acqe_fcoe->event_tag);
                /*
                 * If we are in the middle of FCF failover process, clear
                 * the corresponding FCF bit in the roundrobin bitmap.
@@ -3494,9 +3493,8 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
                        spin_unlock_irq(&phba->hbalock);
                        lpfc_printf_log(phba, KERN_INFO, LOG_FIP |
                                        LOG_DISCOVERY,
-                                       "2773 Start FCF fast failover due "
-                                       "to CVL event: evt_tag:x%x\n",
-                                       acqe_fcoe->event_tag);
+                                       "2773 Start FCF failover per CVL, "
+                                       "evt_tag:x%x\n", acqe_fcoe->event_tag);
                        rc = lpfc_sli4_redisc_fcf_table(phba);
                        if (rc) {
                                lpfc_printf_log(phba, KERN_ERR, LOG_FIP |
@@ -3646,8 +3644,7 @@ void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *phba)
 
        /* Scan FCF table from the first entry to re-discover SAN */
        lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
-                       "2777 Start FCF table scan after FCF "
-                       "rediscovery quiescent period over\n");
+                       "2777 Start post-quiescent FCF table scan\n");
        rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST);
        if (rc)
                lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
@@ -4165,7 +4162,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                goto out_free_active_sgl;
        }
 
-       /* Allocate eligible FCF bmask memory for FCF round robin failover */
+       /* Allocate eligible FCF bmask memory for FCF roundrobin failover */
        longs = (LPFC_SLI4_FCF_TBL_INDX_MAX + BITS_PER_LONG - 1)/BITS_PER_LONG;
        phba->fcf.fcf_rr_bmask = kzalloc(longs * sizeof(unsigned long),
                                         GFP_KERNEL);
@@ -7270,6 +7267,51 @@ lpfc_sli4_unset_hba(struct lpfc_hba *phba)
        return;
 }
 
+/**
+ * lpfc_sli4_xri_exchange_busy_wait - Wait for device XRI exchange busy
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called in the SLI4 code path to wait for completion
+ * of device's XRIs exchange busy. It will check the XRI exchange busy
+ * on outstanding FCP and ELS I/Os every 10ms for up to 10 seconds; after
+ * that, it will check the XRI exchange busy on outstanding FCP and ELS
+ * I/Os every 30 seconds, log error message, and wait forever. Only when
+ * all XRI exchange busy complete, the driver unload shall proceed with
+ * invoking the function reset ioctl mailbox command to the CNA and the
+ * the rest of the driver unload resource release.
+ **/
+static void
+lpfc_sli4_xri_exchange_busy_wait(struct lpfc_hba *phba)
+{
+       int wait_time = 0;
+       int fcp_xri_cmpl = list_empty(&phba->sli4_hba.lpfc_abts_scsi_buf_list);
+       int els_xri_cmpl = list_empty(&phba->sli4_hba.lpfc_abts_els_sgl_list);
+
+       while (!fcp_xri_cmpl || !els_xri_cmpl) {
+               if (wait_time > LPFC_XRI_EXCH_BUSY_WAIT_TMO) {
+                       if (!fcp_xri_cmpl)
+                               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                               "2877 FCP XRI exchange busy "
+                                               "wait time: %d seconds.\n",
+                                               wait_time/1000);
+                       if (!els_xri_cmpl)
+                               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                               "2878 ELS XRI exchange busy "
+                                               "wait time: %d seconds.\n",
+                                               wait_time/1000);
+                       msleep(LPFC_XRI_EXCH_BUSY_WAIT_T2);
+                       wait_time += LPFC_XRI_EXCH_BUSY_WAIT_T2;
+               } else {
+                       msleep(LPFC_XRI_EXCH_BUSY_WAIT_T1);
+                       wait_time += LPFC_XRI_EXCH_BUSY_WAIT_T1;
+               }
+               fcp_xri_cmpl =
+                       list_empty(&phba->sli4_hba.lpfc_abts_scsi_buf_list);
+               els_xri_cmpl =
+                       list_empty(&phba->sli4_hba.lpfc_abts_els_sgl_list);
+       }
+}
+
 /**
  * lpfc_sli4_hba_unset - Unset the fcoe hba
  * @phba: Pointer to HBA context object.
@@ -7315,6 +7357,12 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba)
                spin_unlock_irq(&phba->hbalock);
        }
 
+       /* Abort all iocbs associated with the hba */
+       lpfc_sli_hba_iocb_abort(phba);
+
+       /* Wait for completion of device XRI exchange busy */
+       lpfc_sli4_xri_exchange_busy_wait(phba);
+
        /* Disable PCI subsystem interrupt */
        lpfc_sli4_disable_intr(phba);
 
index 0dfa310cd609318cb0c772f85ea344acdef2c5ea..62d0957e1d4c7dd29add28778f640af952e56b47 100644 (file)
@@ -796,6 +796,34 @@ lpfc_unreg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t rpi,
        return;
 }
 
+/**
+ * lpfc_sli4_unreg_all_rpis - unregister all RPIs for a vport on SLI4 HBA.
+ * @vport: pointer to a vport object.
+ *
+ * This routine sends mailbox command to unregister all active RPIs for
+ * a vport.
+ **/
+void
+lpfc_sli4_unreg_all_rpis(struct lpfc_vport *vport)
+{
+       struct lpfc_hba  *phba  = vport->phba;
+       LPFC_MBOXQ_t     *mbox;
+       int rc;
+
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (mbox) {
+               lpfc_unreg_login(phba, vport->vpi,
+                       vport->vpi + phba->vpi_base, mbox);
+               mbox->u.mb.un.varUnregLogin.rsvd1 = 0x4000 ;
+               mbox->vport = vport;
+               mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+               mbox->context1 = NULL;
+               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+               if (rc == MBX_NOT_FINISHED)
+                       mempool_free(mbox, phba->mbox_mem_pool);
+       }
+}
+
 /**
  * lpfc_reg_vpi - Prepare a mailbox command for registering vport identifier
  * @phba: pointer to lpfc hba data structure.
index 3a658953486cf9a1e73027c9be828a0c12be5e41..f64b65a770b8df3b3f0a3ba47decc0512a8df0a7 100644 (file)
@@ -169,6 +169,7 @@ lpfc_update_stats(struct lpfc_hba *phba, struct  lpfc_scsi_buf *lpfc_cmd)
        spin_lock_irqsave(shost->host_lock, flags);
        if (!vport->stat_data_enabled ||
                vport->stat_data_blocked ||
+               !pnode ||
                !pnode->lat_data ||
                (phba->bucket_type == LPFC_NO_BUCKET)) {
                spin_unlock_irqrestore(shost->host_lock, flags);
@@ -2040,6 +2041,9 @@ lpfc_send_scsi_error_event(struct lpfc_hba *phba, struct lpfc_vport *vport,
        struct lpfc_nodelist *pnode = lpfc_cmd->rdata->pnode;
        unsigned long flags;
 
+       if (!pnode || !NLP_CHK_NODE_ACT(pnode))
+               return;
+
        /* If there is queuefull or busy condition send a scsi event */
        if ((cmnd->result == SAM_STAT_TASK_SET_FULL) ||
                (cmnd->result == SAM_STAT_BUSY)) {
@@ -3226,10 +3230,11 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
        struct lpfc_scsi_buf *lpfc_cmd;
        struct lpfc_iocbq *iocbq;
        struct lpfc_iocbq *iocbqrsp;
+       struct lpfc_nodelist *pnode = rdata->pnode;
        int ret;
        int status;
 
-       if (!rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode))
+       if (!pnode || !NLP_CHK_NODE_ACT(pnode))
                return FAILED;
 
        lpfc_cmd = lpfc_get_scsi_buf(phba);
@@ -3256,7 +3261,7 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
                         "0702 Issue %s to TGT %d LUN %d "
                         "rpi x%x nlp_flag x%x\n",
                         lpfc_taskmgmt_name(task_mgmt_cmd), tgt_id, lun_id,
-                        rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag);
+                        pnode->nlp_rpi, pnode->nlp_flag);
 
        status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING,
                                          iocbq, iocbqrsp, lpfc_cmd->timeout);
index 0d1e187b005ddd366b0545fee2356d1b43df9994..554efa6623f4edab7154e3f1ad23e5be845260c6 100644 (file)
@@ -95,7 +95,7 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe)
                return -ENOMEM;
        /* set consumption flag every once in a while */
        if (!((q->host_index + 1) % LPFC_RELEASE_NOTIFICATION_INTERVAL))
-               bf_set(lpfc_wqe_gen_wqec, &wqe->generic, 1);
+               bf_set(wqe_wqec, &wqe->generic.wqe_com, 1);
 
        lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size);
 
@@ -1735,6 +1735,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        struct lpfc_vport  *vport = pmb->vport;
        struct lpfc_dmabuf *mp;
        struct lpfc_nodelist *ndlp;
+       struct Scsi_Host *shost;
        uint16_t rpi, vpi;
        int rc;
 
@@ -1746,7 +1747,8 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        }
 
        if ((pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) &&
-           (phba->sli_rev == LPFC_SLI_REV4))
+           (phba->sli_rev == LPFC_SLI_REV4) &&
+           (pmb->u.mb.un.varUnregLogin.rsvd1 == 0x0))
                lpfc_sli4_free_rpi(phba, pmb->u.mb.un.varUnregLogin.rpi);
 
        /*
@@ -1765,16 +1767,14 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                        return;
        }
 
-       /* Unreg VPI, if the REG_VPI succeed after VLink failure */
        if ((pmb->u.mb.mbxCommand == MBX_REG_VPI) &&
                !(phba->pport->load_flag & FC_UNLOADING) &&
                !pmb->u.mb.mbxStatus) {
-               lpfc_unreg_vpi(phba, pmb->u.mb.un.varRegVpi.vpi, pmb);
-               pmb->vport = vport;
-               pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-               rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
-               if (rc != MBX_NOT_FINISHED)
-                       return;
+               shost = lpfc_shost_from_vport(vport);
+               spin_lock_irq(shost->host_lock);
+               vport->vpi_state |= LPFC_VPI_REGISTERED;
+               vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+               spin_unlock_irq(shost->host_lock);
        }
 
        if (pmb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
@@ -5921,7 +5921,7 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
  * lpfc_sli4_scmd_to_wqidx_distr - scsi command to SLI4 WQ index distribution
  * @phba: Pointer to HBA context object.
  *
- * This routine performs a round robin SCSI command to SLI4 FCP WQ index
+ * This routine performs a roundrobin SCSI command to SLI4 FCP WQ index
  * distribution.  This is called by __lpfc_sli_issue_iocb_s4() with the hbalock
  * held.
  *
@@ -5965,7 +5965,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
        uint16_t abrt_iotag;
        struct lpfc_iocbq *abrtiocbq;
        struct ulp_bde64 *bpl = NULL;
-       uint32_t els_id = ELS_ID_DEFAULT;
+       uint32_t els_id = LPFC_ELS_ID_DEFAULT;
        int numBdes, i;
        struct ulp_bde64 bde;
 
@@ -5982,7 +5982,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
        memcpy(wqe, &iocbq->iocb, sizeof(union lpfc_wqe));
        abort_tag = (uint32_t) iocbq->iotag;
        xritag = iocbq->sli4_xritag;
-       wqe->words[7] = 0; /* The ct field has moved so reset */
+       wqe->generic.wqe_com.word7 = 0; /* The ct field has moved so reset */
        /* words0-2 bpl convert bde */
        if (iocbq->iocb.un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) {
                numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize /
@@ -6033,109 +6033,117 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                 * contains the FCFI and remote N_Port_ID is
                 * in word 5.
                 */
-
                ct = ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l);
-               bf_set(lpfc_wqe_gen_context, &wqe->generic,
-                               iocbq->iocb.ulpContext);
-
-               bf_set(lpfc_wqe_gen_ct, &wqe->generic, ct);
-               bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0);
+               bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
+                      iocbq->iocb.ulpContext);
+               bf_set(wqe_ct, &wqe->els_req.wqe_com, ct);
+               bf_set(wqe_pu, &wqe->els_req.wqe_com, 0);
                /* CCP CCPE PV PRI in word10 were set in the memcpy */
-
                if (command_type == ELS_COMMAND_FIP) {
                        els_id = ((iocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK)
                                        >> LPFC_FIP_ELS_ID_SHIFT);
                }
-               bf_set(lpfc_wqe_gen_els_id, &wqe->generic, els_id);
-
+               bf_set(wqe_els_id, &wqe->els_req.wqe_com, els_id);
+               bf_set(wqe_dbde, &wqe->els_req.wqe_com, 1);
+               bf_set(wqe_iod, &wqe->els_req.wqe_com, LPFC_WQE_IOD_READ);
+               bf_set(wqe_qosd, &wqe->els_req.wqe_com, 1);
+               bf_set(wqe_lenloc, &wqe->els_req.wqe_com, LPFC_WQE_LENLOC_NONE);
+               bf_set(wqe_ebde_cnt, &wqe->els_req.wqe_com, 0);
        break;
        case CMD_XMIT_SEQUENCE64_CX:
-               bf_set(lpfc_wqe_gen_context, &wqe->generic,
-                                       iocbq->iocb.un.ulpWord[3]);
-               wqe->generic.word3 = 0;
-               bf_set(wqe_rcvoxid, &wqe->generic, iocbq->iocb.ulpContext);
+               bf_set(wqe_ctxt_tag, &wqe->xmit_sequence.wqe_com,
+                      iocbq->iocb.un.ulpWord[3]);
+               bf_set(wqe_rcvoxid, &wqe->xmit_sequence.wqe_com,
+                      iocbq->iocb.ulpContext);
                /* The entire sequence is transmitted for this IOCB */
                xmit_len = total_len;
                cmnd = CMD_XMIT_SEQUENCE64_CR;
        case CMD_XMIT_SEQUENCE64_CR:
-               /* word3 iocb=io_tag32 wqe=payload_offset */
-               /* payload offset used for multilpe outstanding
-                * sequences on the same exchange
-                */
-               wqe->words[3] = 0;
+               /* word3 iocb=io_tag32 wqe=reserved */
+               wqe->xmit_sequence.rsvd3 = 0;
                /* word4 relative_offset memcpy */
                /* word5 r_ctl/df_ctl memcpy */
-               bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0);
+               bf_set(wqe_pu, &wqe->xmit_sequence.wqe_com, 0);
+               bf_set(wqe_dbde, &wqe->xmit_sequence.wqe_com, 1);
+               bf_set(wqe_iod, &wqe->xmit_sequence.wqe_com,
+                      LPFC_WQE_IOD_WRITE);
+               bf_set(wqe_lenloc, &wqe->xmit_sequence.wqe_com,
+                      LPFC_WQE_LENLOC_WORD12);
+               bf_set(wqe_ebde_cnt, &wqe->xmit_sequence.wqe_com, 0);
                wqe->xmit_sequence.xmit_len = xmit_len;
                command_type = OTHER_COMMAND;
        break;
        case CMD_XMIT_BCAST64_CN:
-               /* word3 iocb=iotag32 wqe=payload_len */
-               wqe->words[3] = 0; /* no definition for this in wqe */
+               /* word3 iocb=iotag32 wqe=seq_payload_len */
+               wqe->xmit_bcast64.seq_payload_len = xmit_len;
                /* word4 iocb=rsvd wqe=rsvd */
                /* word5 iocb=rctl/type/df_ctl wqe=rctl/type/df_ctl memcpy */
                /* word6 iocb=ctxt_tag/io_tag wqe=ctxt_tag/xri */
-               bf_set(lpfc_wqe_gen_ct, &wqe->generic,
+               bf_set(wqe_ct, &wqe->xmit_bcast64.wqe_com,
                        ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
+               bf_set(wqe_dbde, &wqe->xmit_bcast64.wqe_com, 1);
+               bf_set(wqe_iod, &wqe->xmit_bcast64.wqe_com, LPFC_WQE_IOD_WRITE);
+               bf_set(wqe_lenloc, &wqe->xmit_bcast64.wqe_com,
+                      LPFC_WQE_LENLOC_WORD3);
+               bf_set(wqe_ebde_cnt, &wqe->xmit_bcast64.wqe_com, 0);
        break;
        case CMD_FCP_IWRITE64_CR:
                command_type = FCP_COMMAND_DATA_OUT;
-               /* The struct for wqe fcp_iwrite has 3 fields that are somewhat
-                * confusing.
-                * word3 is payload_len: byte offset to the sgl entry for the
-                * fcp_command.
-                * word4 is total xfer len, same as the IOCB->ulpParameter.
-                * word5 is initial xfer len 0 = wait for xfer-ready
-                */
-
-               /* Always wait for xfer-ready before sending data */
-               wqe->fcp_iwrite.initial_xfer_len = 0;
-               /* word 4 (xfer length) should have been set on the memcpy */
-
-       /* allow write to fall through to read */
+               /* word3 iocb=iotag wqe=payload_offset_len */
+               /* Add the FCP_CMD and FCP_RSP sizes to get the offset */
+               wqe->fcp_iwrite.payload_offset_len =
+                       xmit_len + sizeof(struct fcp_rsp);
+               /* word4 iocb=parameter wqe=total_xfer_length memcpy */
+               /* word5 iocb=initial_xfer_len wqe=initial_xfer_len memcpy */
+               bf_set(wqe_erp, &wqe->fcp_iwrite.wqe_com,
+                      iocbq->iocb.ulpFCP2Rcvy);
+               bf_set(wqe_lnk, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpXS);
+               /* Always open the exchange */
+               bf_set(wqe_xc, &wqe->fcp_iwrite.wqe_com, 0);
+               bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 1);
+               bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE);
+               bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com,
+                      LPFC_WQE_LENLOC_WORD4);
+               bf_set(wqe_ebde_cnt, &wqe->fcp_iwrite.wqe_com, 0);
+               bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpPU);
+       break;
        case CMD_FCP_IREAD64_CR:
-               /* FCP_CMD is always the 1st sgl entry */
-               wqe->fcp_iread.payload_len =
+               /* word3 iocb=iotag wqe=payload_offset_len */
+               /* Add the FCP_CMD and FCP_RSP sizes to get the offset */
+               wqe->fcp_iread.payload_offset_len =
                        xmit_len + sizeof(struct fcp_rsp);
-
-               /* word 4 (xfer length) should have been set on the memcpy */
-
-               bf_set(lpfc_wqe_gen_erp, &wqe->generic,
-                       iocbq->iocb.ulpFCP2Rcvy);
-               bf_set(lpfc_wqe_gen_lnk, &wqe->generic, iocbq->iocb.ulpXS);
-               /* The XC bit and the XS bit are similar. The driver never
-                * tracked whether or not the exchange was previouslly open.
-                * XC = Exchange create, 0 is create. 1 is already open.
-                * XS = link cmd: 1 do not close the exchange after command.
-                * XS = 0 close exchange when command completes.
-                * The only time we would not set the XC bit is when the XS bit
-                * is set and we are sending our 2nd or greater command on
-                * this exchange.
-                */
+               /* word4 iocb=parameter wqe=total_xfer_length memcpy */
+               /* word5 iocb=initial_xfer_len wqe=initial_xfer_len memcpy */
+               bf_set(wqe_erp, &wqe->fcp_iread.wqe_com,
+                      iocbq->iocb.ulpFCP2Rcvy);
+               bf_set(wqe_lnk, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpXS);
                /* Always open the exchange */
                bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0);
-
-               wqe->words[10] &= 0xffff0000; /* zero out ebde count */
-               bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU);
-               break;
+               bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1);
+               bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ);
+               bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com,
+                      LPFC_WQE_LENLOC_WORD4);
+               bf_set(wqe_ebde_cnt, &wqe->fcp_iread.wqe_com, 0);
+               bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpPU);
+       break;
        case CMD_FCP_ICMND64_CR:
+               /* word3 iocb=IO_TAG wqe=reserved */
+               wqe->fcp_icmd.rsrvd3 = 0;
+               bf_set(wqe_pu, &wqe->fcp_icmd.wqe_com, 0);
                /* Always open the exchange */
-               bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0);
-
-               wqe->words[4] = 0;
-               wqe->words[10] &= 0xffff0000; /* zero out ebde count */
-               bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0);
+               bf_set(wqe_xc, &wqe->fcp_icmd.wqe_com, 0);
+               bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 1);
+               bf_set(wqe_iod, &wqe->fcp_icmd.wqe_com, LPFC_WQE_IOD_WRITE);
+               bf_set(wqe_qosd, &wqe->fcp_icmd.wqe_com, 1);
+               bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com,
+                      LPFC_WQE_LENLOC_NONE);
+               bf_set(wqe_ebde_cnt, &wqe->fcp_icmd.wqe_com, 0);
        break;
        case CMD_GEN_REQUEST64_CR:
-               /* word3 command length is described as byte offset to the
-                * rsp_data. Would always be 16, sizeof(struct sli4_sge)
-                * sgl[0] = cmnd
-                * sgl[1] = rsp.
-                *
-                */
-               wqe->gen_req.command_len = xmit_len;
-               /* Word4 parameter  copied in the memcpy */
-               /* Word5 [rctl, type, df_ctl, la] copied in memcpy */
+               /* word3 iocb=IO_TAG wqe=request_payload_len */
+               wqe->gen_req.request_payload_len = xmit_len;
+               /* word4 iocb=parameter wqe=relative_offset memcpy */
+               /* word5 [rctl, type, df_ctl, la] copied in memcpy */
                /* word6 context tag copied in memcpy */
                if (iocbq->iocb.ulpCt_h  || iocbq->iocb.ulpCt_l) {
                        ct = ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l);
@@ -6144,31 +6152,39 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                                ct, iocbq->iocb.ulpCommand);
                        return IOCB_ERROR;
                }
-               bf_set(lpfc_wqe_gen_ct, &wqe->generic, 0);
-               bf_set(wqe_tmo, &wqe->gen_req.wqe_com,
-                       iocbq->iocb.ulpTimeout);
-
-               bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU);
+               bf_set(wqe_ct, &wqe->gen_req.wqe_com, 0);
+               bf_set(wqe_tmo, &wqe->gen_req.wqe_com, iocbq->iocb.ulpTimeout);
+               bf_set(wqe_pu, &wqe->gen_req.wqe_com, iocbq->iocb.ulpPU);
+               bf_set(wqe_dbde, &wqe->gen_req.wqe_com, 1);
+               bf_set(wqe_iod, &wqe->gen_req.wqe_com, LPFC_WQE_IOD_READ);
+               bf_set(wqe_qosd, &wqe->gen_req.wqe_com, 1);
+               bf_set(wqe_lenloc, &wqe->gen_req.wqe_com, LPFC_WQE_LENLOC_NONE);
+               bf_set(wqe_ebde_cnt, &wqe->gen_req.wqe_com, 0);
                command_type = OTHER_COMMAND;
        break;
        case CMD_XMIT_ELS_RSP64_CX:
                /* words0-2 BDE memcpy */
-               /* word3 iocb=iotag32 wqe=rsvd */
-               wqe->words[3] = 0;
+               /* word3 iocb=iotag32 wqe=response_payload_len */
+               wqe->xmit_els_rsp.response_payload_len = xmit_len;
                /* word4 iocb=did wge=rsvd. */
-               wqe->words[4] = 0;
+               wqe->xmit_els_rsp.rsvd4 = 0;
                /* word5 iocb=rsvd wge=did */
                bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest,
                         iocbq->iocb.un.elsreq64.remoteID);
-
-               bf_set(lpfc_wqe_gen_ct, &wqe->generic,
-                       ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
-
-               bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU);
-               bf_set(wqe_rcvoxid, &wqe->generic, iocbq->iocb.ulpContext);
+               bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com,
+                      ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
+               bf_set(wqe_pu, &wqe->xmit_els_rsp.wqe_com, iocbq->iocb.ulpPU);
+               bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com,
+                      iocbq->iocb.ulpContext);
                if (!iocbq->iocb.ulpCt_h && iocbq->iocb.ulpCt_l)
-                       bf_set(lpfc_wqe_gen_context, &wqe->generic,
+                       bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com,
                               iocbq->vport->vpi + phba->vpi_base);
+               bf_set(wqe_dbde, &wqe->xmit_els_rsp.wqe_com, 1);
+               bf_set(wqe_iod, &wqe->xmit_els_rsp.wqe_com, LPFC_WQE_IOD_WRITE);
+               bf_set(wqe_qosd, &wqe->xmit_els_rsp.wqe_com, 1);
+               bf_set(wqe_lenloc, &wqe->xmit_els_rsp.wqe_com,
+                      LPFC_WQE_LENLOC_WORD3);
+               bf_set(wqe_ebde_cnt, &wqe->xmit_els_rsp.wqe_com, 0);
                command_type = OTHER_COMMAND;
        break;
        case CMD_CLOSE_XRI_CN:
@@ -6193,15 +6209,19 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                else
                        bf_set(abort_cmd_ia, &wqe->abort_cmd, 0);
                bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG);
-               wqe->words[5] = 0;
-               bf_set(lpfc_wqe_gen_ct, &wqe->generic,
+               /* word5 iocb=CONTEXT_TAG|IO_TAG wqe=reserved */
+               wqe->abort_cmd.rsrvd5 = 0;
+               bf_set(wqe_ct, &wqe->abort_cmd.wqe_com,
                        ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
                abort_tag = iocbq->iocb.un.acxri.abortIoTag;
                /*
                 * The abort handler will send us CMD_ABORT_XRI_CN or
                 * CMD_CLOSE_XRI_CN and the fw only accepts CMD_ABORT_XRI_CX
                 */
-               bf_set(lpfc_wqe_gen_command, &wqe->generic, CMD_ABORT_XRI_CX);
+               bf_set(wqe_cmnd, &wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX);
+               bf_set(wqe_qosd, &wqe->abort_cmd.wqe_com, 1);
+               bf_set(wqe_lenloc, &wqe->abort_cmd.wqe_com,
+                      LPFC_WQE_LENLOC_NONE);
                cmnd = CMD_ABORT_XRI_CX;
                command_type = OTHER_COMMAND;
                xritag = 0;
@@ -6235,18 +6255,14 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                bf_set(wqe_xmit_bls_pt, &wqe->xmit_bls_rsp.wqe_dest, 0x1);
                bf_set(wqe_ctxt_tag, &wqe->xmit_bls_rsp.wqe_com,
                       iocbq->iocb.ulpContext);
+               bf_set(wqe_qosd, &wqe->xmit_bls_rsp.wqe_com, 1);
+               bf_set(wqe_lenloc, &wqe->xmit_bls_rsp.wqe_com,
+                      LPFC_WQE_LENLOC_NONE);
                /* Overwrite the pre-set comnd type with OTHER_COMMAND */
                command_type = OTHER_COMMAND;
        break;
        case CMD_XRI_ABORTED_CX:
        case CMD_CREATE_XRI_CR: /* Do we expect to use this? */
-               /* words0-2 are all 0's no bde */
-               /* word3 and word4 are rsvrd */
-               wqe->words[3] = 0;
-               wqe->words[4] = 0;
-               /* word5 iocb=rsvd wge=did */
-               /* There is no remote port id in the IOCB? */
-               /* Let this fall through and fail */
        case CMD_IOCB_FCP_IBIDIR64_CR: /* bidirectional xfer */
        case CMD_FCP_TSEND64_CX: /* Target mode send xfer-ready */
        case CMD_FCP_TRSP64_CX: /* Target mode rcv */
@@ -6257,16 +6273,14 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                                iocbq->iocb.ulpCommand);
                return IOCB_ERROR;
        break;
-
        }
-       bf_set(lpfc_wqe_gen_xri, &wqe->generic, xritag);
-       bf_set(lpfc_wqe_gen_request_tag, &wqe->generic, iocbq->iotag);
-       wqe->generic.abort_tag = abort_tag;
-       bf_set(lpfc_wqe_gen_cmd_type, &wqe->generic, command_type);
-       bf_set(lpfc_wqe_gen_command, &wqe->generic, cmnd);
-       bf_set(lpfc_wqe_gen_class, &wqe->generic, iocbq->iocb.ulpClass);
-       bf_set(lpfc_wqe_gen_cq_id, &wqe->generic, LPFC_WQE_CQ_ID_DEFAULT);
-
+       bf_set(wqe_xri_tag, &wqe->generic.wqe_com, xritag);
+       bf_set(wqe_reqtag, &wqe->generic.wqe_com, iocbq->iotag);
+       wqe->generic.wqe_com.abort_tag = abort_tag;
+       bf_set(wqe_cmd_type, &wqe->generic.wqe_com, command_type);
+       bf_set(wqe_cmnd, &wqe->generic.wqe_com, cmnd);
+       bf_set(wqe_class, &wqe->generic.wqe_com, iocbq->iocb.ulpClass);
+       bf_set(wqe_cqid, &wqe->generic.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
        return 0;
 }
 
@@ -7257,25 +7271,26 @@ lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 }
 
 /**
- * lpfc_sli_issue_abort_iotag - Abort function for a command iocb
+ * lpfc_sli_abort_iotag_issue - Issue abort for a command iocb
  * @phba: Pointer to HBA context object.
  * @pring: Pointer to driver SLI ring object.
  * @cmdiocb: Pointer to driver command iocb object.
  *
- * This function issues an abort iocb for the provided command
- * iocb. This function is called with hbalock held.
- * The function returns 0 when it fails due to memory allocation
- * failure or when the command iocb is an abort request.
+ * This function issues an abort iocb for the provided command iocb down to
+ * the port. Other than the case the outstanding command iocb is an abort
+ * request, this function issues abort out unconditionally. This function is
+ * called with hbalock held. The function returns 0 when it fails due to
+ * memory allocation failure or when the command iocb is an abort request.
  **/
-int
-lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+static int
+lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                           struct lpfc_iocbq *cmdiocb)
 {
        struct lpfc_vport *vport = cmdiocb->vport;
        struct lpfc_iocbq *abtsiocbp;
        IOCB_t *icmd = NULL;
        IOCB_t *iabt = NULL;
-       int retval = IOCB_ERROR;
+       int retval;
 
        /*
         * There are certain command types we don't want to abort.  And we
@@ -7288,18 +7303,6 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
            (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0)
                return 0;
 
-       /* If we're unloading, don't abort iocb on the ELS ring, but change the
-        * callback so that nothing happens when it finishes.
-        */
-       if ((vport->load_flag & FC_UNLOADING) &&
-           (pring->ringno == LPFC_ELS_RING)) {
-               if (cmdiocb->iocb_flag & LPFC_IO_FABRIC)
-                       cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl;
-               else
-                       cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl;
-               goto abort_iotag_exit;
-       }
-
        /* issue ABTS for this IOCB based on iotag */
        abtsiocbp = __lpfc_sli_get_iocbq(phba);
        if (abtsiocbp == NULL)
@@ -7344,6 +7347,63 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
        if (retval)
                __lpfc_sli_release_iocbq(phba, abtsiocbp);
+
+       /*
+        * Caller to this routine should check for IOCB_ERROR
+        * and handle it properly.  This routine no longer removes
+        * iocb off txcmplq and call compl in case of IOCB_ERROR.
+        */
+       return retval;
+}
+
+/**
+ * lpfc_sli_issue_abort_iotag - Abort function for a command iocb
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @cmdiocb: Pointer to driver command iocb object.
+ *
+ * This function issues an abort iocb for the provided command iocb. In case
+ * of unloading, the abort iocb will not be issued to commands on the ELS
+ * ring. Instead, the callback function shall be changed to those commands
+ * so that nothing happens when them finishes. This function is called with
+ * hbalock held. The function returns 0 when the command iocb is an abort
+ * request.
+ **/
+int
+lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+                          struct lpfc_iocbq *cmdiocb)
+{
+       struct lpfc_vport *vport = cmdiocb->vport;
+       int retval = IOCB_ERROR;
+       IOCB_t *icmd = NULL;
+
+       /*
+        * There are certain command types we don't want to abort.  And we
+        * don't want to abort commands that are already in the process of
+        * being aborted.
+        */
+       icmd = &cmdiocb->iocb;
+       if (icmd->ulpCommand == CMD_ABORT_XRI_CN ||
+           icmd->ulpCommand == CMD_CLOSE_XRI_CN ||
+           (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0)
+               return 0;
+
+       /*
+        * If we're unloading, don't abort iocb on the ELS ring, but change
+        * the callback so that nothing happens when it finishes.
+        */
+       if ((vport->load_flag & FC_UNLOADING) &&
+           (pring->ringno == LPFC_ELS_RING)) {
+               if (cmdiocb->iocb_flag & LPFC_IO_FABRIC)
+                       cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl;
+               else
+                       cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl;
+               goto abort_iotag_exit;
+       }
+
+       /* Now, we try to issue the abort to the cmdiocb out */
+       retval = lpfc_sli_abort_iotag_issue(phba, pring, cmdiocb);
+
 abort_iotag_exit:
        /*
         * Caller to this routine should check for IOCB_ERROR
@@ -7353,6 +7413,62 @@ abort_iotag_exit:
        return retval;
 }
 
+/**
+ * lpfc_sli_iocb_ring_abort - Unconditionally abort all iocbs on an iocb ring
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ *
+ * This function aborts all iocbs in the given ring and frees all the iocb
+ * objects in txq. This function issues abort iocbs unconditionally for all
+ * the iocb commands in txcmplq. The iocbs in the txcmplq is not guaranteed
+ * to complete before the return of this function. The caller is not required
+ * to hold any locks.
+ **/
+static void
+lpfc_sli_iocb_ring_abort(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
+{
+       LIST_HEAD(completions);
+       struct lpfc_iocbq *iocb, *next_iocb;
+
+       if (pring->ringno == LPFC_ELS_RING)
+               lpfc_fabric_abort_hba(phba);
+
+       spin_lock_irq(&phba->hbalock);
+
+       /* Take off all the iocbs on txq for cancelling */
+       list_splice_init(&pring->txq, &completions);
+       pring->txq_cnt = 0;
+
+       /* Next issue ABTS for everything on the txcmplq */
+       list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
+               lpfc_sli_abort_iotag_issue(phba, pring, iocb);
+
+       spin_unlock_irq(&phba->hbalock);
+
+       /* Cancel all the IOCBs from the completions list */
+       lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
+                             IOERR_SLI_ABORTED);
+}
+
+/**
+ * lpfc_sli_hba_iocb_abort - Abort all iocbs to an hba.
+ * @phba: pointer to lpfc HBA data structure.
+ *
+ * This routine will abort all pending and outstanding iocbs to an HBA.
+ **/
+void
+lpfc_sli_hba_iocb_abort(struct lpfc_hba *phba)
+{
+       struct lpfc_sli *psli = &phba->sli;
+       struct lpfc_sli_ring *pring;
+       int i;
+
+       for (i = 0; i < psli->num_rings; i++) {
+               pring = &psli->ring[i];
+               lpfc_sli_iocb_ring_abort(phba, pring);
+       }
+}
+
 /**
  * lpfc_sli_validate_fcp_iocb - find commands associated with a vport or LUN
  * @iocbq: Pointer to driver iocb object.
@@ -12242,13 +12358,15 @@ lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index)
        /* Issue the mailbox command asynchronously */
        mboxq->vport = phba->pport;
        mboxq->mbox_cmpl = lpfc_mbx_cmpl_fcf_scan_read_fcf_rec;
+
+       spin_lock_irq(&phba->hbalock);
+       phba->hba_flag |= FCF_TS_INPROG;
+       spin_unlock_irq(&phba->hbalock);
+
        rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
        if (rc == MBX_NOT_FINISHED)
                error = -EIO;
        else {
-               spin_lock_irq(&phba->hbalock);
-               phba->hba_flag |= FCF_DISC_INPROGRESS;
-               spin_unlock_irq(&phba->hbalock);
                /* Reset eligible FCF count for new scan */
                if (fcf_index == LPFC_FCOE_FCF_GET_FIRST)
                        phba->fcf.eligible_fcf_cnt = 0;
@@ -12258,21 +12376,21 @@ fail_fcf_scan:
        if (error) {
                if (mboxq)
                        lpfc_sli4_mbox_cmd_free(phba, mboxq);
-               /* FCF scan failed, clear FCF_DISC_INPROGRESS flag */
+               /* FCF scan failed, clear FCF_TS_INPROG flag */
                spin_lock_irq(&phba->hbalock);
-               phba->hba_flag &= ~FCF_DISC_INPROGRESS;
+               phba->hba_flag &= ~FCF_TS_INPROG;
                spin_unlock_irq(&phba->hbalock);
        }
        return error;
 }
 
 /**
- * lpfc_sli4_fcf_rr_read_fcf_rec - Read hba fcf record for round robin fcf.
+ * lpfc_sli4_fcf_rr_read_fcf_rec - Read hba fcf record for roundrobin fcf.
  * @phba: pointer to lpfc hba data structure.
  * @fcf_index: FCF table entry offset.
  *
  * This routine is invoked to read an FCF record indicated by @fcf_index
- * and to use it for FLOGI round robin FCF failover.
+ * and to use it for FLOGI roundrobin FCF failover.
  *
  * Return 0 if the mailbox command is submitted sucessfully, none 0
  * otherwise.
@@ -12318,7 +12436,7 @@ fail_fcf_read:
  * @fcf_index: FCF table entry offset.
  *
  * This routine is invoked to read an FCF record indicated by @fcf_index to
- * determine whether it's eligible for FLOGI round robin failover list.
+ * determine whether it's eligible for FLOGI roundrobin failover list.
  *
  * Return 0 if the mailbox command is submitted sucessfully, none 0
  * otherwise.
@@ -12364,7 +12482,7 @@ fail_fcf_read:
  *
  * This routine is to get the next eligible FCF record index in a round
  * robin fashion. If the next eligible FCF record index equals to the
- * initial round robin FCF record index, LPFC_FCOE_FCF_NEXT_NONE (0xFFFF)
+ * initial roundrobin FCF record index, LPFC_FCOE_FCF_NEXT_NONE (0xFFFF)
  * shall be returned, otherwise, the next eligible FCF record's index
  * shall be returned.
  **/
@@ -12392,28 +12510,10 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)
                return LPFC_FCOE_FCF_NEXT_NONE;
        }
 
-       /* Check roundrobin failover index bmask stop condition */
-       if (next_fcf_index == phba->fcf.fcf_rr_init_indx) {
-               if (!(phba->fcf.fcf_flag & FCF_REDISC_RRU)) {
-                       lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
-                                       "2847 Round robin failover FCF index "
-                                       "search hit stop condition:x%x\n",
-                                       next_fcf_index);
-                       return LPFC_FCOE_FCF_NEXT_NONE;
-               }
-               /* The roundrobin failover index bmask updated, start over */
-               lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
-                               "2848 Round robin failover FCF index bmask "
-                               "updated, start over\n");
-               spin_lock_irq(&phba->hbalock);
-               phba->fcf.fcf_flag &= ~FCF_REDISC_RRU;
-               spin_unlock_irq(&phba->hbalock);
-               return phba->fcf.fcf_rr_init_indx;
-       }
-
        lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
-                       "2845 Get next round robin failover "
-                       "FCF index x%x\n", next_fcf_index);
+                       "2845 Get next roundrobin failover FCF (x%x)\n",
+                       next_fcf_index);
+
        return next_fcf_index;
 }
 
@@ -12422,7 +12522,7 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine sets the FCF record index in to the eligible bmask for
- * round robin failover search. It checks to make sure that the index
+ * roundrobin failover search. It checks to make sure that the index
  * does not go beyond the range of the driver allocated bmask dimension
  * before setting the bit.
  *
@@ -12434,22 +12534,16 @@ lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index)
 {
        if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
                lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
-                               "2610 HBA FCF index reached driver's "
-                               "book keeping dimension: fcf_index:%d, "
-                               "driver_bmask_max:%d\n",
+                               "2610 FCF (x%x) reached driver's book "
+                               "keeping dimension:x%x\n",
                                fcf_index, LPFC_SLI4_FCF_TBL_INDX_MAX);
                return -EINVAL;
        }
        /* Set the eligible FCF record index bmask */
        set_bit(fcf_index, phba->fcf.fcf_rr_bmask);
 
-       /* Set the roundrobin index bmask updated */
-       spin_lock_irq(&phba->hbalock);
-       phba->fcf.fcf_flag |= FCF_REDISC_RRU;
-       spin_unlock_irq(&phba->hbalock);
-
        lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
-                       "2790 Set FCF index x%x to round robin failover "
+                       "2790 Set FCF (x%x) to roundrobin FCF failover "
                        "bmask\n", fcf_index);
 
        return 0;
@@ -12460,7 +12554,7 @@ lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index)
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine clears the FCF record index from the eligible bmask for
- * round robin failover search. It checks to make sure that the index
+ * roundrobin failover search. It checks to make sure that the index
  * does not go beyond the range of the driver allocated bmask dimension
  * before clearing the bit.
  **/
@@ -12469,9 +12563,8 @@ lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
 {
        if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
                lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
-                               "2762 HBA FCF index goes beyond driver's "
-                               "book keeping dimension: fcf_index:%d, "
-                               "driver_bmask_max:%d\n",
+                               "2762 FCF (x%x) reached driver's book "
+                               "keeping dimension:x%x\n",
                                fcf_index, LPFC_SLI4_FCF_TBL_INDX_MAX);
                return;
        }
@@ -12479,7 +12572,7 @@ lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
        clear_bit(fcf_index, phba->fcf.fcf_rr_bmask);
 
        lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
-                       "2791 Clear FCF index x%x from round robin failover "
+                       "2791 Clear FCF (x%x) from roundrobin failover "
                        "bmask\n", fcf_index);
 }
 
@@ -12530,8 +12623,7 @@ lpfc_mbx_cmpl_redisc_fcf_table(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
                }
        } else {
                lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
-                               "2775 Start FCF rediscovery quiescent period "
-                               "wait timer before scaning FCF table\n");
+                               "2775 Start FCF rediscover quiescent timer\n");
                /*
                 * Start FCF rediscovery wait timer for pending FCF
                 * before rescan FCF record table.
index a0ca572ec28be4a4105a08f4360459aa8f091abf..c4483feb8b71a32a4198175ac91a0c142a647e61 100644 (file)
  *******************************************************************/
 
 #define LPFC_ACTIVE_MBOX_WAIT_CNT               100
+#define LPFC_XRI_EXCH_BUSY_WAIT_TMO            10000
+#define LPFC_XRI_EXCH_BUSY_WAIT_T1             10
+#define LPFC_XRI_EXCH_BUSY_WAIT_T2              30000
 #define LPFC_RELEASE_NOTIFICATION_INTERVAL     32
 #define LPFC_GET_QE_REL_INT                    32
 #define LPFC_RPI_LOW_WATER_MARK                        10
 
+#define LPFC_UNREG_FCF                          1
+#define LPFC_SKIP_UNREG_FCF                     0
+
 /* Amount of time in seconds for waiting FCF rediscovery to complete */
 #define LPFC_FCF_REDISCOVER_WAIT_TMO           2000 /* msec */
 
@@ -163,9 +169,8 @@ struct lpfc_fcf {
 #define FCF_REDISC_PEND        0x80 /* FCF rediscovery pending */
 #define FCF_REDISC_EVT 0x100 /* FCF rediscovery event to worker thread */
 #define FCF_REDISC_FOV 0x200 /* Post FCF rediscovery fast failover */
-#define FCF_REDISC_RRU 0x400 /* Roundrobin bitmap updated */
+#define FCF_REDISC_PROG (FCF_REDISC_PEND | FCF_REDISC_EVT)
        uint32_t addr_mode;
-       uint16_t fcf_rr_init_indx;
        uint32_t eligible_fcf_cnt;
        struct lpfc_fcf_rec current_rec;
        struct lpfc_fcf_rec failover_rec;
index f93120e4c7961e632e6fb79c9aa2ee28ad029e38..7a1b5b112a0bca1c26481063875576430a7ac664 100644 (file)
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.3.17"
+#define LPFC_DRIVER_VERSION "8.3.18"
 #define LPFC_DRIVER_NAME               "lpfc"
 #define LPFC_SP_DRIVER_HANDLER_NAME    "lpfc:sp"
 #define LPFC_FP_DRIVER_HANDLER_NAME    "lpfc:fp"
index d3c9cdee292b11cdcf44cd9b163bec3e7749814d..eb29d508513148653fb492df24cee9ab0b14cb17 100644 (file)
@@ -10,7 +10,7 @@
  *        2 of the License, or (at your option) any later version.
  *
  * FILE                : megaraid_sas.c
- * Version     : v00.00.04.17.1-rc1
+ * Version     : v00.00.04.31-rc1
  *
  * Authors:
  *     (email-id : megaraidlinux@lsi.com)
@@ -56,6 +56,15 @@ module_param_named(poll_mode_io, poll_mode_io, int, 0);
 MODULE_PARM_DESC(poll_mode_io,
        "Complete cmds from IO path, (default=0)");
 
+/*
+ * Number of sectors per IO command
+ * Will be set in megasas_init_mfi if user does not provide
+ */
+static unsigned int max_sectors;
+module_param_named(max_sectors, max_sectors, int, 0);
+MODULE_PARM_DESC(max_sectors,
+       "Maximum number of sectors per IO command");
+
 MODULE_LICENSE("GPL");
 MODULE_VERSION(MEGASAS_VERSION);
 MODULE_AUTHOR("megaraidlinux@lsi.com");
@@ -103,6 +112,7 @@ static int megasas_poll_wait_aen;
 static DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait);
 static u32 support_poll_for_event;
 static u32 megasas_dbg_lvl;
+static u32 support_device_change;
 
 /* define lock for aen poll */
 spinlock_t poll_aen_lock;
@@ -718,6 +728,10 @@ static int
 megasas_check_reset_gen2(struct megasas_instance *instance,
                struct megasas_register_set __iomem *regs)
 {
+       if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+               return 1;
+       }
+
        return 0;
 }
 
@@ -930,6 +944,7 @@ megasas_make_sgl_skinny(struct megasas_instance *instance,
                        mfi_sgl->sge_skinny[i].length = sg_dma_len(os_sgl);
                        mfi_sgl->sge_skinny[i].phys_addr =
                                                sg_dma_address(os_sgl);
+                       mfi_sgl->sge_skinny[i].flag = 0;
                }
        }
        return sge_count;
@@ -1557,6 +1572,28 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
        }
 }
 
+static void
+megasas_internal_reset_defer_cmds(struct megasas_instance *instance);
+
+static void
+process_fw_state_change_wq(struct work_struct *work);
+
+void megasas_do_ocr(struct megasas_instance *instance)
+{
+       if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
+       (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
+       (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR)) {
+               *instance->consumer     = MEGASAS_ADPRESET_INPROG_SIGN;
+       }
+       instance->instancet->disable_intr(instance->reg_set);
+       instance->adprecovery   = MEGASAS_ADPRESET_SM_INFAULT;
+       instance->issuepend_done = 0;
+
+       atomic_set(&instance->fw_outstanding, 0);
+       megasas_internal_reset_defer_cmds(instance);
+       process_fw_state_change_wq(&instance->work_init);
+}
+
 /**
  * megasas_wait_for_outstanding -      Wait for all outstanding cmds
  * @instance:                          Adapter soft state
@@ -1574,6 +1611,8 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
        unsigned long flags;
        struct list_head clist_local;
        struct megasas_cmd *reset_cmd;
+       u32 fw_state;
+       u8 kill_adapter_flag;
 
        spin_lock_irqsave(&instance->hba_lock, flags);
        adprecovery = instance->adprecovery;
@@ -1659,7 +1698,45 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
                msleep(1000);
        }
 
-       if (atomic_read(&instance->fw_outstanding)) {
+       i = 0;
+       kill_adapter_flag = 0;
+       do {
+               fw_state = instance->instancet->read_fw_status_reg(
+                                       instance->reg_set) & MFI_STATE_MASK;
+               if ((fw_state == MFI_STATE_FAULT) &&
+                       (instance->disableOnlineCtrlReset == 0)) {
+                       if (i == 3) {
+                               kill_adapter_flag = 2;
+                               break;
+                       }
+                       megasas_do_ocr(instance);
+                       kill_adapter_flag = 1;
+
+                       /* wait for 1 secs to let FW finish the pending cmds */
+                       msleep(1000);
+               }
+               i++;
+       } while (i <= 3);
+
+       if (atomic_read(&instance->fw_outstanding) &&
+                                       !kill_adapter_flag) {
+               if (instance->disableOnlineCtrlReset == 0) {
+
+                       megasas_do_ocr(instance);
+
+                       /* wait for 5 secs to let FW finish the pending cmds */
+                       for (i = 0; i < wait_time; i++) {
+                               int outstanding =
+                                       atomic_read(&instance->fw_outstanding);
+                               if (!outstanding)
+                                       return SUCCESS;
+                               msleep(1000);
+                       }
+               }
+       }
+
+       if (atomic_read(&instance->fw_outstanding) ||
+                                       (kill_adapter_flag == 2)) {
                printk(KERN_NOTICE "megaraid_sas: pending cmds after reset\n");
                /*
                * Send signal to FW to stop processing any pending cmds.
@@ -2669,6 +2746,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
                        return -ENOMEM;
                }
 
+               memset(cmd->frame, 0, total_sz);
                cmd->frame->io.context = cmd->index;
                cmd->frame->io.pad_0 = 0;
        }
@@ -3585,6 +3663,27 @@ static int megasas_io_attach(struct megasas_instance *instance)
                        instance->max_fw_cmds - MEGASAS_INT_CMDS;
        host->this_id = instance->init_id;
        host->sg_tablesize = instance->max_num_sge;
+       /*
+        * Check if the module parameter value for max_sectors can be used
+        */
+       if (max_sectors && max_sectors < instance->max_sectors_per_req)
+               instance->max_sectors_per_req = max_sectors;
+       else {
+               if (max_sectors) {
+                       if (((instance->pdev->device ==
+                               PCI_DEVICE_ID_LSI_SAS1078GEN2) ||
+                               (instance->pdev->device ==
+                               PCI_DEVICE_ID_LSI_SAS0079GEN2)) &&
+                               (max_sectors <= MEGASAS_MAX_SECTORS)) {
+                               instance->max_sectors_per_req = max_sectors;
+                       } else {
+                       printk(KERN_INFO "megasas: max_sectors should be > 0"
+                               "and <= %d (or < 1MB for GEN2 controller)\n",
+                               instance->max_sectors_per_req);
+                       }
+               }
+       }
+
        host->max_sectors = instance->max_sectors_per_req;
        host->cmd_per_lun = 128;
        host->max_channel = MEGASAS_MAX_CHANNELS - 1;
@@ -4658,6 +4757,15 @@ megasas_sysfs_show_support_poll_for_event(struct device_driver *dd, char *buf)
 static DRIVER_ATTR(support_poll_for_event, S_IRUGO,
                        megasas_sysfs_show_support_poll_for_event, NULL);
 
+ static ssize_t
+megasas_sysfs_show_support_device_change(struct device_driver *dd, char *buf)
+{
+       return sprintf(buf, "%u\n", support_device_change);
+}
+
+static DRIVER_ATTR(support_device_change, S_IRUGO,
+                       megasas_sysfs_show_support_device_change, NULL);
+
 static ssize_t
 megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
 {
@@ -4978,6 +5086,7 @@ static int __init megasas_init(void)
               MEGASAS_EXT_VERSION);
 
        support_poll_for_event = 2;
+       support_device_change = 1;
 
        memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info));
 
@@ -5026,8 +5135,17 @@ static int __init megasas_init(void)
        if (rval)
                goto err_dcf_poll_mode_io;
 
+       rval = driver_create_file(&megasas_pci_driver.driver,
+                               &driver_attr_support_device_change);
+       if (rval)
+               goto err_dcf_support_device_change;
+
        return rval;
 
+err_dcf_support_device_change:
+       driver_remove_file(&megasas_pci_driver.driver,
+                 &driver_attr_poll_mode_io);
+
 err_dcf_poll_mode_io:
        driver_remove_file(&megasas_pci_driver.driver,
                           &driver_attr_dbg_lvl);
@@ -5057,6 +5175,10 @@ static void __exit megasas_exit(void)
                           &driver_attr_poll_mode_io);
        driver_remove_file(&megasas_pci_driver.driver,
                           &driver_attr_dbg_lvl);
+       driver_remove_file(&megasas_pci_driver.driver,
+                       &driver_attr_support_poll_for_event);
+       driver_remove_file(&megasas_pci_driver.driver,
+                       &driver_attr_support_device_change);
        driver_remove_file(&megasas_pci_driver.driver,
                           &driver_attr_release_date);
        driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
index 16a4f68a34b0db0fa48145eb42c0f90aae25ec07..ad16f5e600462955bec5c5e4878119a4093f1ae7 100644 (file)
@@ -18,9 +18,9 @@
 /*
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION                        "00.00.04.17.1-rc1"
-#define MEGASAS_RELDATE                        "Oct. 29, 2009"
-#define MEGASAS_EXT_VERSION            "Thu. Oct. 29, 11:41:51 PST 2009"
+#define MEGASAS_VERSION                        "00.00.04.31-rc1"
+#define MEGASAS_RELDATE                        "May 3, 2010"
+#define MEGASAS_EXT_VERSION            "Mon. May 3, 11:41:51 PST 2010"
 
 /*
  * Device IDs
@@ -706,6 +706,7 @@ struct megasas_ctrl_info {
 #define MEGASAS_MAX_LD_IDS                     (MEGASAS_MAX_LD_CHANNELS * \
                                                MEGASAS_MAX_DEV_PER_CHANNEL)
 
+#define MEGASAS_MAX_SECTORS                    (2*1024)
 #define MEGASAS_DBG_LVL                                1
 
 #define MEGASAS_FW_BUSY                                1
index e88bbdde49c5066b4bfb9fa2d8b5822115777cd8..0433ea6f27c9c2db97c464ca238afce39ebd0fcb 100644 (file)
@@ -452,10 +452,6 @@ void osd_end_request(struct osd_request *or)
 {
        struct request *rq = or->request;
 
-       _osd_free_seg(or, &or->set_attr);
-       _osd_free_seg(or, &or->enc_get_attr);
-       _osd_free_seg(or, &or->get_attr);
-
        if (rq) {
                if (rq->next_rq) {
                        _put_request(rq->next_rq);
@@ -464,6 +460,12 @@ void osd_end_request(struct osd_request *or)
 
                _put_request(rq);
        }
+
+       _osd_free_seg(or, &or->get_attr);
+       _osd_free_seg(or, &or->enc_get_attr);
+       _osd_free_seg(or, &or->set_attr);
+       _osd_free_seg(or, &or->cdb_cont);
+
        _osd_request_free(or);
 }
 EXPORT_SYMBOL(osd_end_request);
@@ -547,6 +549,12 @@ static int _osd_realloc_seg(struct osd_request *or,
        return 0;
 }
 
+static int _alloc_cdb_cont(struct osd_request *or, unsigned total_bytes)
+{
+       OSD_DEBUG("total_bytes=%d\n", total_bytes);
+       return _osd_realloc_seg(or, &or->cdb_cont, total_bytes);
+}
+
 static int _alloc_set_attr_list(struct osd_request *or,
        const struct osd_attr *oa, unsigned nelem, unsigned add_bytes)
 {
@@ -885,6 +893,199 @@ int osd_req_read_kern(struct osd_request *or,
 }
 EXPORT_SYMBOL(osd_req_read_kern);
 
+static int _add_sg_continuation_descriptor(struct osd_request *or,
+       const struct osd_sg_entry *sglist, unsigned numentries, u64 *len)
+{
+       struct osd_sg_continuation_descriptor *oscd;
+       u32 oscd_size;
+       unsigned i;
+       int ret;
+
+       oscd_size = sizeof(*oscd) + numentries * sizeof(oscd->entries[0]);
+
+       if (!or->cdb_cont.total_bytes) {
+               /* First time, jump over the header, we will write to:
+                *      cdb_cont.buff + cdb_cont.total_bytes
+                */
+               or->cdb_cont.total_bytes =
+                               sizeof(struct osd_continuation_segment_header);
+       }
+
+       ret = _alloc_cdb_cont(or, or->cdb_cont.total_bytes + oscd_size);
+       if (unlikely(ret))
+               return ret;
+
+       oscd = or->cdb_cont.buff + or->cdb_cont.total_bytes;
+       oscd->hdr.type = cpu_to_be16(SCATTER_GATHER_LIST);
+       oscd->hdr.pad_length = 0;
+       oscd->hdr.length = cpu_to_be32(oscd_size - sizeof(*oscd));
+
+       *len = 0;
+       /* copy the sg entries and convert to network byte order */
+       for (i = 0; i < numentries; i++) {
+               oscd->entries[i].offset = cpu_to_be64(sglist[i].offset);
+               oscd->entries[i].len    = cpu_to_be64(sglist[i].len);
+               *len += sglist[i].len;
+       }
+
+       or->cdb_cont.total_bytes += oscd_size;
+       OSD_DEBUG("total_bytes=%d oscd_size=%d numentries=%d\n",
+                 or->cdb_cont.total_bytes, oscd_size, numentries);
+       return 0;
+}
+
+static int _osd_req_finalize_cdb_cont(struct osd_request *or, const u8 *cap_key)
+{
+       struct request_queue *req_q = osd_request_queue(or->osd_dev);
+       struct bio *bio;
+       struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
+       struct osd_continuation_segment_header *cont_seg_hdr;
+
+       if (!or->cdb_cont.total_bytes)
+               return 0;
+
+       cont_seg_hdr = or->cdb_cont.buff;
+       cont_seg_hdr->format = CDB_CONTINUATION_FORMAT_V2;
+       cont_seg_hdr->service_action = cdbh->varlen_cdb.service_action;
+
+       /* create a bio for continuation segment */
+       bio = bio_map_kern(req_q, or->cdb_cont.buff, or->cdb_cont.total_bytes,
+                          GFP_KERNEL);
+       if (unlikely(!bio))
+               return -ENOMEM;
+
+       bio->bi_rw |= REQ_WRITE;
+
+       /* integrity check the continuation before the bio is linked
+        * with the other data segments since the continuation
+        * integrity is separate from the other data segments.
+        */
+       osd_sec_sign_data(cont_seg_hdr->integrity_check, bio, cap_key);
+
+       cdbh->v2.cdb_continuation_length = cpu_to_be32(or->cdb_cont.total_bytes);
+
+       /* we can't use _req_append_segment, because we need to link in the
+        * continuation bio to the head of the bio list - the
+        * continuation segment (if it exists) is always the first segment in
+        * the out data buffer.
+        */
+       bio->bi_next = or->out.bio;
+       or->out.bio = bio;
+       or->out.total_bytes += or->cdb_cont.total_bytes;
+
+       return 0;
+}
+
+/* osd_req_write_sg: Takes a @bio that points to the data out buffer and an
+ * @sglist that has the scatter gather entries. Scatter-gather enables a write
+ * of multiple none-contiguous areas of an object, in a single call. The extents
+ * may overlap and/or be in any order. The only constrain is that:
+ *     total_bytes(sglist) >= total_bytes(bio)
+ */
+int osd_req_write_sg(struct osd_request *or,
+       const struct osd_obj_id *obj, struct bio *bio,
+       const struct osd_sg_entry *sglist, unsigned numentries)
+{
+       u64 len;
+       int ret = _add_sg_continuation_descriptor(or, sglist, numentries, &len);
+
+       if (ret)
+               return ret;
+       osd_req_write(or, obj, 0, bio, len);
+
+       return 0;
+}
+EXPORT_SYMBOL(osd_req_write_sg);
+
+/* osd_req_read_sg: Read multiple extents of an object into @bio
+ * See osd_req_write_sg
+ */
+int osd_req_read_sg(struct osd_request *or,
+       const struct osd_obj_id *obj, struct bio *bio,
+       const struct osd_sg_entry *sglist, unsigned numentries)
+{
+       u64 len;
+       int ret = _add_sg_continuation_descriptor(or, sglist, numentries, &len);
+
+       if (ret)
+               return ret;
+       osd_req_read(or, obj, 0, bio, len);
+
+       return 0;
+}
+EXPORT_SYMBOL(osd_req_read_sg);
+
+/* SG-list write/read Kern API
+ *
+ * osd_req_{write,read}_sg_kern takes an array of @buff pointers and an array
+ * of sg_entries. @numentries indicates how many pointers and sg_entries there
+ * are.  By requiring an array of buff pointers. This allows a caller to do a
+ * single write/read and scatter into multiple buffers.
+ * NOTE: Each buffer + len should not cross a page boundary.
+ */
+static struct bio *_create_sg_bios(struct osd_request *or,
+       void **buff, const struct osd_sg_entry *sglist, unsigned numentries)
+{
+       struct request_queue *q = osd_request_queue(or->osd_dev);
+       struct bio *bio;
+       unsigned i;
+
+       bio = bio_kmalloc(GFP_KERNEL, numentries);
+       if (unlikely(!bio)) {
+               OSD_DEBUG("Faild to allocate BIO size=%u\n", numentries);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       for (i = 0; i < numentries; i++) {
+               unsigned offset = offset_in_page(buff[i]);
+               struct page *page = virt_to_page(buff[i]);
+               unsigned len = sglist[i].len;
+               unsigned added_len;
+
+               BUG_ON(offset + len > PAGE_SIZE);
+               added_len = bio_add_pc_page(q, bio, page, len, offset);
+               if (unlikely(len != added_len)) {
+                       OSD_DEBUG("bio_add_pc_page len(%d) != added_len(%d)\n",
+                                 len, added_len);
+                       bio_put(bio);
+                       return ERR_PTR(-ENOMEM);
+               }
+       }
+
+       return bio;
+}
+
+int osd_req_write_sg_kern(struct osd_request *or,
+       const struct osd_obj_id *obj, void **buff,
+       const struct osd_sg_entry *sglist, unsigned numentries)
+{
+       struct bio *bio = _create_sg_bios(or, buff, sglist, numentries);
+       if (IS_ERR(bio))
+               return PTR_ERR(bio);
+
+       bio->bi_rw |= REQ_WRITE;
+       osd_req_write_sg(or, obj, bio, sglist, numentries);
+
+       return 0;
+}
+EXPORT_SYMBOL(osd_req_write_sg_kern);
+
+int osd_req_read_sg_kern(struct osd_request *or,
+       const struct osd_obj_id *obj, void **buff,
+       const struct osd_sg_entry *sglist, unsigned numentries)
+{
+       struct bio *bio = _create_sg_bios(or, buff, sglist, numentries);
+       if (IS_ERR(bio))
+               return PTR_ERR(bio);
+
+       osd_req_read_sg(or, obj, bio, sglist, numentries);
+
+       return 0;
+}
+EXPORT_SYMBOL(osd_req_read_sg_kern);
+
+
+
 void osd_req_get_attributes(struct osd_request *or,
        const struct osd_obj_id *obj)
 {
@@ -1218,17 +1419,18 @@ int osd_req_add_get_attr_page(struct osd_request *or,
        or->get_attr.buff = attar_page;
        or->get_attr.total_bytes = max_page_len;
 
-       or->set_attr.buff = set_one_attr->val_ptr;
-       or->set_attr.total_bytes = set_one_attr->len;
-
        cdbh->attrs_page.get_attr_page = cpu_to_be32(page_id);
        cdbh->attrs_page.get_attr_alloc_length = cpu_to_be32(max_page_len);
-       /* ocdb->attrs_page.get_attr_offset; */
+
+       if (!set_one_attr || !set_one_attr->attr_page)
+               return 0; /* The set is optional */
+
+       or->set_attr.buff = set_one_attr->val_ptr;
+       or->set_attr.total_bytes = set_one_attr->len;
 
        cdbh->attrs_page.set_attr_page = cpu_to_be32(set_one_attr->attr_page);
        cdbh->attrs_page.set_attr_id = cpu_to_be32(set_one_attr->attr_id);
        cdbh->attrs_page.set_attr_length = cpu_to_be32(set_one_attr->len);
-       /* ocdb->attrs_page.set_attr_offset; */
        return 0;
 }
 EXPORT_SYMBOL(osd_req_add_get_attr_page);
@@ -1248,11 +1450,14 @@ static int _osd_req_finalize_attr_page(struct osd_request *or)
        if (ret)
                return ret;
 
+       if (or->set_attr.total_bytes == 0)
+               return 0;
+
        /* set one value */
        cdbh->attrs_page.set_attr_offset =
                osd_req_encode_offset(or, or->out.total_bytes, &out_padding);
 
-       ret = _req_append_segment(or, out_padding, &or->enc_get_attr, NULL,
+       ret = _req_append_segment(or, out_padding, &or->set_attr, NULL,
                                  &or->out);
        return ret;
 }
@@ -1276,7 +1481,8 @@ static inline void osd_sec_parms_set_in_offset(bool is_v1,
 }
 
 static int _osd_req_finalize_data_integrity(struct osd_request *or,
-       bool has_in, bool has_out, u64 out_data_bytes, const u8 *cap_key)
+       bool has_in, bool has_out, struct bio *out_data_bio, u64 out_data_bytes,
+       const u8 *cap_key)
 {
        struct osd_security_parameters *sec_parms = _osd_req_sec_params(or);
        int ret;
@@ -1307,7 +1513,7 @@ static int _osd_req_finalize_data_integrity(struct osd_request *or,
                or->out.last_seg = NULL;
 
                /* they are now all chained to request sign them all together */
-               osd_sec_sign_data(&or->out_data_integ, or->out.req->bio,
+               osd_sec_sign_data(&or->out_data_integ, out_data_bio,
                                  cap_key);
        }
 
@@ -1403,6 +1609,8 @@ int osd_finalize_request(struct osd_request *or,
 {
        struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
        bool has_in, has_out;
+        /* Save for data_integrity without the cdb_continuation */
+       struct bio *out_data_bio = or->out.bio;
        u64 out_data_bytes = or->out.total_bytes;
        int ret;
 
@@ -1418,9 +1626,14 @@ int osd_finalize_request(struct osd_request *or,
        osd_set_caps(&or->cdb, cap);
 
        has_in = or->in.bio || or->get_attr.total_bytes;
-       has_out = or->out.bio || or->set_attr.total_bytes ||
-               or->enc_get_attr.total_bytes;
+       has_out = or->out.bio || or->cdb_cont.total_bytes ||
+               or->set_attr.total_bytes || or->enc_get_attr.total_bytes;
 
+       ret = _osd_req_finalize_cdb_cont(or, cap_key);
+       if (ret) {
+               OSD_DEBUG("_osd_req_finalize_cdb_cont failed\n");
+               return ret;
+       }
        ret = _init_blk_request(or, has_in, has_out);
        if (ret) {
                OSD_DEBUG("_init_blk_request failed\n");
@@ -1458,7 +1671,8 @@ int osd_finalize_request(struct osd_request *or,
        }
 
        ret = _osd_req_finalize_data_integrity(or, has_in, has_out,
-                                              out_data_bytes, cap_key);
+                                              out_data_bio, out_data_bytes,
+                                              cap_key);
        if (ret)
                return ret;
 
index 4b8765785aeb0cb3020acdb51b1b0218e42bac34..cf89091e4c3d3befec59b89425792dcad23e2a87 100644 (file)
@@ -1594,10 +1594,12 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance)
        cfg_entry = &ccn_hcam->cfg_entry;
        fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
 
-       pmcraid_info
-               ("CCN(%x): %x type: %x lost: %x flags: %x res: %x:%x:%x:%x\n",
+       pmcraid_info("CCN(%x): %x timestamp: %llx type: %x lost: %x flags: %x \
+                res: %x:%x:%x:%x\n",
                 pinstance->ccn.hcam->ilid,
                 pinstance->ccn.hcam->op_code,
+               ((pinstance->ccn.hcam->timestamp1) |
+               ((pinstance->ccn.hcam->timestamp2 & 0xffffffffLL) << 32)),
                 pinstance->ccn.hcam->notification_type,
                 pinstance->ccn.hcam->notification_lost,
                 pinstance->ccn.hcam->flags,
@@ -1850,6 +1852,7 @@ static void pmcraid_process_ccn(struct pmcraid_cmd *cmd)
  *   none
  */
 static void pmcraid_initiate_reset(struct pmcraid_instance *);
+static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd);
 
 static void pmcraid_process_ldn(struct pmcraid_cmd *cmd)
 {
@@ -1881,6 +1884,10 @@ static void pmcraid_process_ldn(struct pmcraid_cmd *cmd)
                                               lock_flags);
                        return;
                }
+               if (fd_ioasc == PMCRAID_IOASC_TIME_STAMP_OUT_OF_SYNC) {
+                       pinstance->timestamp_error = 1;
+                       pmcraid_set_timestamp(cmd);
+               }
        } else {
                dev_info(&pinstance->pdev->dev,
                        "Host RCB(LDN) failed with IOASC: 0x%08X\n", ioasc);
@@ -3363,7 +3370,7 @@ static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen)
        sg_size = buflen;
 
        for (i = 0; i < num_elem; i++) {
-               page = alloc_pages(GFP_KERNEL|GFP_DMA, order);
+               page = alloc_pages(GFP_KERNEL|GFP_DMA|__GFP_ZERO, order);
                if (!page) {
                        for (j = i - 1; j >= 0; j--)
                                __free_pages(sg_page(&scatterlist[j]), order);
@@ -3739,6 +3746,7 @@ static long pmcraid_ioctl_passthrough(
        unsigned long request_buffer;
        unsigned long request_offset;
        unsigned long lock_flags;
+       void *ioasa;
        u32 ioasc;
        int request_size;
        int buffer_size;
@@ -3780,6 +3788,11 @@ static long pmcraid_ioctl_passthrough(
        rc = __copy_from_user(buffer,
                             (struct pmcraid_passthrough_ioctl_buffer *) arg,
                             sizeof(struct pmcraid_passthrough_ioctl_buffer));
+
+       ioasa =
+       (void *)(arg +
+               offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa));
+
        if (rc) {
                pmcraid_err("ioctl: can't copy passthrough buffer\n");
                rc = -EFAULT;
@@ -3947,22 +3960,14 @@ static long pmcraid_ioctl_passthrough(
        }
 
 out_handle_response:
-       /* If the command failed for any reason, copy entire IOASA buffer and
-        * return IOCTL success. If copying IOASA to user-buffer fails, return
+       /* copy entire IOASA buffer and return IOCTL success.
+        * If copying IOASA to user-buffer fails, return
         * EFAULT
         */
-       if (PMCRAID_IOASC_SENSE_KEY(le32_to_cpu(cmd->ioa_cb->ioasa.ioasc))) {
-               void *ioasa =
-                   (void *)(arg +
-                   offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa));
-
-               pmcraid_info("command failed with %x\n",
-                            le32_to_cpu(cmd->ioa_cb->ioasa.ioasc));
-               if (copy_to_user(ioasa, &cmd->ioa_cb->ioasa,
-                                sizeof(struct pmcraid_ioasa))) {
-                       pmcraid_err("failed to copy ioasa buffer to user\n");
-                       rc = -EFAULT;
-               }
+       if (copy_to_user(ioasa, &cmd->ioa_cb->ioasa,
+               sizeof(struct pmcraid_ioasa))) {
+               pmcraid_err("failed to copy ioasa buffer to user\n");
+               rc = -EFAULT;
        }
 
        /* If the data transfer was from device, copy the data onto user
@@ -5147,6 +5152,16 @@ static void pmcraid_release_buffers(struct pmcraid_instance *pinstance)
                pinstance->inq_data = NULL;
                pinstance->inq_data_baddr = 0;
        }
+
+       if (pinstance->timestamp_data != NULL) {
+               pci_free_consistent(pinstance->pdev,
+                                   sizeof(struct pmcraid_timestamp_data),
+                                   pinstance->timestamp_data,
+                                   pinstance->timestamp_data_baddr);
+
+               pinstance->timestamp_data = NULL;
+               pinstance->timestamp_data_baddr = 0;
+       }
 }
 
 /**
@@ -5205,6 +5220,20 @@ static int __devinit pmcraid_init_buffers(struct pmcraid_instance *pinstance)
                return -ENOMEM;
        }
 
+       /* allocate DMAable memory for set timestamp data buffer */
+       pinstance->timestamp_data = pci_alloc_consistent(
+                                       pinstance->pdev,
+                                       sizeof(struct pmcraid_timestamp_data),
+                                       &pinstance->timestamp_data_baddr);
+
+       if (pinstance->timestamp_data == NULL) {
+               pmcraid_err("couldn't allocate DMA memory for \
+                               set time_stamp \n");
+               pmcraid_release_buffers(pinstance);
+               return -ENOMEM;
+       }
+
+
        /* Initialize all the command blocks and add them to free pool. No
         * need to lock (free_pool_lock) as this is done in initialization
         * itself
@@ -5609,6 +5638,68 @@ static void pmcraid_set_supported_devs(struct pmcraid_cmd *cmd)
        return;
 }
 
+/**
+ * pmcraid_set_timestamp - set the timestamp to IOAFP
+ *
+ * @cmd: pointer to pmcraid_cmd structure
+ *
+ * Return Value
+ *  0 for success or non-zero for failure cases
+ */
+static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd)
+{
+       struct pmcraid_instance *pinstance = cmd->drv_inst;
+       struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb;
+       __be32 time_stamp_len = cpu_to_be32(PMCRAID_TIMESTAMP_LEN);
+       struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl;
+
+       struct timeval tv;
+       __le64 timestamp;
+
+       do_gettimeofday(&tv);
+       timestamp = tv.tv_sec * 1000;
+
+       pinstance->timestamp_data->timestamp[0] = (__u8)(timestamp);
+       pinstance->timestamp_data->timestamp[1] = (__u8)((timestamp) >> 8);
+       pinstance->timestamp_data->timestamp[2] = (__u8)((timestamp) >> 16);
+       pinstance->timestamp_data->timestamp[3] = (__u8)((timestamp) >> 24);
+       pinstance->timestamp_data->timestamp[4] = (__u8)((timestamp) >> 32);
+       pinstance->timestamp_data->timestamp[5] = (__u8)((timestamp)  >> 40);
+
+       pmcraid_reinit_cmdblk(cmd);
+       ioarcb->request_type = REQ_TYPE_SCSI;
+       ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE);
+       ioarcb->cdb[0] = PMCRAID_SCSI_SET_TIMESTAMP;
+       ioarcb->cdb[1] = PMCRAID_SCSI_SERVICE_ACTION;
+       memcpy(&(ioarcb->cdb[6]), &time_stamp_len, sizeof(time_stamp_len));
+
+       ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) +
+                                       offsetof(struct pmcraid_ioarcb,
+                                               add_data.u.ioadl[0]));
+       ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc));
+       ioarcb->ioarcb_bus_addr &= ~(0x1FULL);
+
+       ioarcb->request_flags0 |= NO_LINK_DESCS;
+       ioarcb->request_flags0 |= TRANSFER_DIR_WRITE;
+       ioarcb->data_transfer_length =
+               cpu_to_le32(sizeof(struct pmcraid_timestamp_data));
+       ioadl = &(ioarcb->add_data.u.ioadl[0]);
+       ioadl->flags = IOADL_FLAGS_LAST_DESC;
+       ioadl->address = cpu_to_le64(pinstance->timestamp_data_baddr);
+       ioadl->data_len = cpu_to_le32(sizeof(struct pmcraid_timestamp_data));
+
+       if (!pinstance->timestamp_error) {
+               pinstance->timestamp_error = 0;
+               pmcraid_send_cmd(cmd, pmcraid_set_supported_devs,
+                        PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler);
+       } else {
+               pmcraid_send_cmd(cmd, pmcraid_return_cmd,
+                        PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler);
+               return;
+       }
+}
+
+
 /**
  * pmcraid_init_res_table - Initialize the resource table
  * @cmd:  pointer to pmcraid command struct
@@ -5720,7 +5811,7 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd)
 
        /* release the resource list lock */
        spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags);
-       pmcraid_set_supported_devs(cmd);
+       pmcraid_set_timestamp(cmd);
 }
 
 /**
@@ -6054,10 +6145,10 @@ out_init:
 static void __exit pmcraid_exit(void)
 {
        pmcraid_netlink_release();
-       class_destroy(pmcraid_class);
        unregister_chrdev_region(MKDEV(pmcraid_major, 0),
                                 PMCRAID_MAX_ADAPTERS);
        pci_unregister_driver(&pmcraid_driver);
+       class_destroy(pmcraid_class);
 }
 
 module_init(pmcraid_init);
index 6cfa0145a1d7f088ea41926c400154bfcd0b989d..1134279604e805780f84607c523bbdd647685f24 100644 (file)
@@ -42,7 +42,7 @@
  */
 #define PMCRAID_DRIVER_NAME            "PMC MaxRAID"
 #define PMCRAID_DEVFILE                        "pmcsas"
-#define PMCRAID_DRIVER_VERSION         "2.0.2"
+#define PMCRAID_DRIVER_VERSION         "2.0.3"
 #define PMCRAID_DRIVER_DATE            __DATE__
 
 #define PMCRAID_FW_VERSION_1           0x002
 #define PMCRAID_IOASC_IR_INVALID_RESOURCE_HANDLE        0x05250000
 #define PMCRAID_IOASC_AC_TERMINATED_BY_HOST            0x0B5A0000
 #define PMCRAID_IOASC_UA_BUS_WAS_RESET                 0x06290000
+#define PMCRAID_IOASC_TIME_STAMP_OUT_OF_SYNC           0x06908B00
 #define PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER                0x06298000
 
 /* Driver defined IOASCs */
@@ -561,6 +562,17 @@ struct pmcraid_inquiry_data {
        __u8    reserved3[16];
 };
 
+#define PMCRAID_TIMESTAMP_LEN          12
+#define PMCRAID_REQ_TM_STR_LEN         6
+#define PMCRAID_SCSI_SET_TIMESTAMP     0xA4
+#define PMCRAID_SCSI_SERVICE_ACTION    0x0F
+
+struct pmcraid_timestamp_data {
+       __u8 reserved1[4];
+       __u8 timestamp[PMCRAID_REQ_TM_STR_LEN];         /* current time value */
+       __u8 reserved2[2];
+};
+
 /* pmcraid_cmd - LLD representation of SCSI command */
 struct pmcraid_cmd {
 
@@ -568,7 +580,6 @@ struct pmcraid_cmd {
        struct pmcraid_control_block *ioa_cb;
        dma_addr_t ioa_cb_bus_addr;
        dma_addr_t dma_handle;
-       u8 *sense_buffer;
 
        /* pointer to mid layer structure of SCSI commands */
        struct scsi_cmnd *scsi_cmd;
@@ -705,6 +716,9 @@ struct pmcraid_instance {
        struct pmcraid_inquiry_data *inq_data;
        dma_addr_t  inq_data_baddr;
 
+       struct pmcraid_timestamp_data *timestamp_data;
+       dma_addr_t  timestamp_data_baddr;
+
        /* size of configuration table entry, varies based on the firmware */
        u32     config_table_entry_size;
 
@@ -791,6 +805,7 @@ struct pmcraid_instance {
 #define SHUTDOWN_NONE               0x0
 #define SHUTDOWN_NORMAL             0x1
 #define SHUTDOWN_ABBREV             0x2
+       u32 timestamp_error:1; /* indicate set timestamp for out of sync */
 
 };
 
@@ -1056,10 +1071,10 @@ struct pmcraid_passthrough_ioctl_buffer {
 #define PMCRAID_PASSTHROUGH_IOCTL    'F'
 
 #define DRV_IOCTL(n, size) \
-    _IOC(_IOC_READ|_IOC_WRITE, PMCRAID_DRIVER_IOCTL, (n), (size))
+       _IOC(_IOC_READ|_IOC_WRITE, PMCRAID_DRIVER_IOCTL, (n), (size))
 
 #define FMW_IOCTL(n, size) \
-    _IOC(_IOC_READ|_IOC_WRITE, PMCRAID_PASSTHROUGH_IOCTL,  (n), (size))
+       _IOC(_IOC_READ|_IOC_WRITE, PMCRAID_PASSTHROUGH_IOCTL,  (n), (size))
 
 /*
  * _ARGSIZE: macro that gives size of the argument type passed to an IOCTL cmd.
index 2ff4342ae362ecfae79b03f86ec460a08dc40888..bc8194f74625f923b16b05a88faa3b6bb63ffb2e 100644 (file)
@@ -1538,6 +1538,10 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
        if (!fcport)
                return;
 
+       /* Now that the rport has been deleted, set the fcport state to
+          FCS_DEVICE_DEAD */
+       atomic_set(&fcport->state, FCS_DEVICE_DEAD);
+
        /*
         * Transport has effectively 'deleted' the rport, clear
         * all local references.
index fdfbf83a63309316c394bf360d189c8bae7a9b33..31a4121a2be1651543d97cd99be7534c86a6acb9 100644 (file)
@@ -1306,6 +1306,125 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
        return rval;
 }
 
+static int
+qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, struct qla_hw_data *ha,
+       uint8_t is_update)
+{
+       uint32_t start = 0;
+       int valid = 0;
+
+       bsg_job->reply->reply_payload_rcv_len = 0;
+
+       if (unlikely(pci_channel_offline(ha->pdev)))
+               return -EINVAL;
+
+       start = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
+       if (start > ha->optrom_size)
+               return -EINVAL;
+
+       if (ha->optrom_state != QLA_SWAITING)
+               return -EBUSY;
+
+       ha->optrom_region_start = start;
+
+       if (is_update) {
+               if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
+                       valid = 1;
+               else if (start == (ha->flt_region_boot * 4) ||
+                   start == (ha->flt_region_fw * 4))
+                       valid = 1;
+               else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
+                   IS_QLA8XXX_TYPE(ha))
+                       valid = 1;
+               if (!valid) {
+                       qla_printk(KERN_WARNING, ha,
+                           "Invalid start region 0x%x/0x%x.\n",
+                           start, bsg_job->request_payload.payload_len);
+                       return -EINVAL;
+               }
+
+               ha->optrom_region_size = start +
+                   bsg_job->request_payload.payload_len > ha->optrom_size ?
+                   ha->optrom_size - start :
+                   bsg_job->request_payload.payload_len;
+               ha->optrom_state = QLA_SWRITING;
+       } else {
+               ha->optrom_region_size = start +
+                   bsg_job->reply_payload.payload_len > ha->optrom_size ?
+                   ha->optrom_size - start :
+                   bsg_job->reply_payload.payload_len;
+               ha->optrom_state = QLA_SREADING;
+       }
+
+       ha->optrom_buffer = vmalloc(ha->optrom_region_size);
+       if (!ha->optrom_buffer) {
+               qla_printk(KERN_WARNING, ha,
+                   "Read: Unable to allocate memory for optrom retrieval "
+                   "(%x).\n", ha->optrom_region_size);
+
+               ha->optrom_state = QLA_SWAITING;
+               return -ENOMEM;
+       }
+
+       memset(ha->optrom_buffer, 0, ha->optrom_region_size);
+       return 0;
+}
+
+static int
+qla2x00_read_optrom(struct fc_bsg_job *bsg_job)
+{
+       struct Scsi_Host *host = bsg_job->shost;
+       scsi_qla_host_t *vha = shost_priv(host);
+       struct qla_hw_data *ha = vha->hw;
+       int rval = 0;
+
+       rval = qla2x00_optrom_setup(bsg_job, ha, 0);
+       if (rval)
+               return rval;
+
+       ha->isp_ops->read_optrom(vha, ha->optrom_buffer,
+           ha->optrom_region_start, ha->optrom_region_size);
+
+       sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+           bsg_job->reply_payload.sg_cnt, ha->optrom_buffer,
+           ha->optrom_region_size);
+
+       bsg_job->reply->reply_payload_rcv_len = ha->optrom_region_size;
+       bsg_job->reply->result = DID_OK;
+       vfree(ha->optrom_buffer);
+       ha->optrom_buffer = NULL;
+       ha->optrom_state = QLA_SWAITING;
+       bsg_job->job_done(bsg_job);
+       return rval;
+}
+
+static int
+qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
+{
+       struct Scsi_Host *host = bsg_job->shost;
+       scsi_qla_host_t *vha = shost_priv(host);
+       struct qla_hw_data *ha = vha->hw;
+       int rval = 0;
+
+       rval = qla2x00_optrom_setup(bsg_job, ha, 1);
+       if (rval)
+               return rval;
+
+       sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+           bsg_job->request_payload.sg_cnt, ha->optrom_buffer,
+           ha->optrom_region_size);
+
+       ha->isp_ops->write_optrom(vha, ha->optrom_buffer,
+           ha->optrom_region_start, ha->optrom_region_size);
+
+       bsg_job->reply->result = DID_OK;
+       vfree(ha->optrom_buffer);
+       ha->optrom_buffer = NULL;
+       ha->optrom_state = QLA_SWAITING;
+       bsg_job->job_done(bsg_job);
+       return rval;
+}
+
 static int
 qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
 {
@@ -1328,6 +1447,12 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
        case QL_VND_FCP_PRIO_CFG_CMD:
                return qla24xx_proc_fcp_prio_cfg_cmd(bsg_job);
 
+       case QL_VND_READ_FLASH:
+               return qla2x00_read_optrom(bsg_job);
+
+       case QL_VND_UPDATE_FLASH:
+               return qla2x00_update_optrom(bsg_job);
+
        default:
                bsg_job->reply->result = (DID_ERROR << 16);
                bsg_job->job_done(bsg_job);
index cc7c52f87a11a3332868ccf2bfac3d9aae31c9d2..074a999c7017a8cd05c4763c49042e464177b2f8 100644 (file)
@@ -14,6 +14,8 @@
 #define QL_VND_A84_MGMT_CMD    0x04
 #define QL_VND_IIDMA           0x05
 #define QL_VND_FCP_PRIO_CFG_CMD        0x06
+#define QL_VND_READ_FLASH      0x07
+#define QL_VND_UPDATE_FLASH    0x08
 
 /* BSG definations for interpreting CommandSent field */
 #define INT_DEF_LB_LOOPBACK_CMD         0
index e1d3ad40a946cc4c206a0755053bfcc67fa60ac2..3a22effced5fa1a94996582b9fd13ccf151d8861 100644 (file)
@@ -1700,9 +1700,7 @@ typedef struct fc_port {
        atomic_t state;
        uint32_t flags;
 
-       int port_login_retry_count;
        int login_retry;
-       atomic_t port_down_timer;
 
        struct fc_rport *rport, *drport;
        u32 supported_classes;
index c33dec827e1ecd3dde4742d67f44f0afe694b83f..9382a816c133104e45108dff7e4a0a2ced2271b8 100644 (file)
@@ -92,6 +92,7 @@ extern int ql2xshiftctondsd;
 extern int ql2xdbwr;
 extern int ql2xdontresethba;
 extern int ql2xasynctmfenable;
+extern int ql2xgffidenable;
 extern int ql2xenabledif;
 extern int ql2xenablehba_err_chk;
 extern int ql2xtargetreset;
index 3cafbef40737e55f99d815060f9d22566efe080c..259f511374933cb4d7463098c26e746809e75d1b 100644 (file)
@@ -71,7 +71,7 @@ qla2x00_ctx_sp_free(srb_t *sp)
        struct srb_iocb *iocb = ctx->u.iocb_cmd;
        struct scsi_qla_host *vha = sp->fcport->vha;
 
-       del_timer_sync(&iocb->timer);
+       del_timer(&iocb->timer);
        kfree(iocb);
        kfree(ctx);
        mempool_free(sp, sp->fcport->vha->hw->srb_mempool);
@@ -1344,6 +1344,13 @@ cont_alloc:
                qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for "
                    "firmware dump!!!\n", dump_size / 1024);
 
+               if (ha->fce) {
+                       dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
+                           ha->fce_dma);
+                       ha->fce = NULL;
+                       ha->fce_dma = 0;
+               }
+
                if (ha->eft) {
                        dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft,
                            ha->eft_dma);
@@ -1818,14 +1825,14 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
                qla2x00_init_response_q_entries(rsp);
        }
 
-       spin_lock_irqsave(&ha->vport_slock, flags);
+       spin_lock(&ha->vport_slock);
        /* Clear RSCN queue. */
        list_for_each_entry(vp, &ha->vp_list, list) {
                vp->rscn_in_ptr = 0;
                vp->rscn_out_ptr = 0;
        }
 
-       spin_unlock_irqrestore(&ha->vport_slock, flags);
+       spin_unlock(&ha->vport_slock);
 
        ha->isp_ops->config_rings(vha);
 
@@ -2916,21 +2923,13 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
 void
 qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
 {
-       struct qla_hw_data *ha = vha->hw;
-
        fcport->vha = vha;
        fcport->login_retry = 0;
-       fcport->port_login_retry_count = ha->port_down_retry_count *
-           PORT_RETRY_TIME;
-       atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
-           PORT_RETRY_TIME);
        fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
 
        qla2x00_iidma_fcport(vha, fcport);
-
-       atomic_set(&fcport->state, FCS_ONLINE);
-
        qla2x00_reg_remote_port(vha, fcport);
+       atomic_set(&fcport->state, FCS_ONLINE);
 }
 
 /*
@@ -3292,8 +3291,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
                        continue;
 
                /* Bypass ports whose FCP-4 type is not FCP_SCSI */
-               if (new_fcport->fc4_type != FC4_TYPE_FCP_SCSI &&
-                   new_fcport->fc4_type != FC4_TYPE_UNKNOWN)
+               if (ql2xgffidenable &&
+                   (new_fcport->fc4_type != FC4_TYPE_FCP_SCSI &&
+                   new_fcport->fc4_type != FC4_TYPE_UNKNOWN))
                        continue;
 
                /* Locate matching device in database. */
index 579f02854665a41ab8ae7cdfa0e53155fbcbd374..5f94430b42f03974fda76e9f1f969cedbf3e9047 100644 (file)
@@ -992,8 +992,8 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
        ha = vha->hw;
 
        DEBUG18(printk(KERN_DEBUG
-           "%s(%ld): Executing cmd sp %p, pid=%ld, prot_op=%u.\n", __func__,
-           vha->host_no, sp, cmd->serial_number, scsi_get_prot_op(sp->cmd)));
+           "%s(%ld): Executing cmd sp %p, prot_op=%u.\n", __func__,
+           vha->host_no, sp, scsi_get_prot_op(sp->cmd)));
 
        cmd_pkt->vp_index = sp->fcport->vp_idx;
 
index e0e43d9e7ed130346d27f86c7f60b933c2fea6cf..1f06ddd9bdd10cdbe6526de1deaaab194a19118e 100644 (file)
@@ -1240,12 +1240,6 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
        case LSC_SCODE_NPORT_USED:
                data[0] = MBS_LOOP_ID_USED;
                break;
-       case LSC_SCODE_CMD_FAILED:
-               if ((iop[1] & 0xff) == 0x05) {
-                       data[0] = MBS_NOT_LOGGED_IN;
-                       break;
-               }
-               /* Fall through. */
        default:
                data[0] = MBS_COMMAND_ERROR;
                break;
@@ -1431,9 +1425,8 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
                rsp->status_srb = sp;
 
        DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
-           "cmd=%p pid=%ld\n", __func__, sp->fcport->vha->host_no,
-           cp->device->channel, cp->device->id, cp->device->lun, cp,
-           cp->serial_number));
+           "cmd=%p\n", __func__, sp->fcport->vha->host_no,
+           cp->device->channel, cp->device->id, cp->device->lun, cp));
        if (sense_len)
                DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, sense_len));
 }
@@ -1757,6 +1750,8 @@ check_scsi_status:
        case CS_INCOMPLETE:
        case CS_PORT_UNAVAILABLE:
        case CS_TIMEOUT:
+       case CS_RESET:
+
                /*
                 * We are going to have the fc class block the rport
                 * while we try to recover so instruct the mid layer
@@ -1781,10 +1776,6 @@ check_scsi_status:
                        qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
                break;
 
-       case CS_RESET:
-               cp->result = DID_TRANSPORT_DISRUPTED << 16;
-               break;
-
        case CS_ABORTED:
                cp->result = DID_RESET << 16;
                break;
@@ -1801,10 +1792,10 @@ out:
        if (logit)
                DEBUG2(qla_printk(KERN_INFO, ha,
                    "scsi(%ld:%d:%d) FCP command status: 0x%x-0x%x (0x%x) "
-                   "oxid=0x%x ser=0x%lx cdb=%02x%02x%02x len=0x%x "
+                   "oxid=0x%x cdb=%02x%02x%02x len=0x%x "
                    "rsp_info=0x%x resid=0x%x fw_resid=0x%x\n", vha->host_no,
                    cp->device->id, cp->device->lun, comp_status, scsi_status,
-                   cp->result, ox_id, cp->serial_number, cp->cmnd[0],
+                   cp->result, ox_id, cp->cmnd[0],
                    cp->cmnd[1], cp->cmnd[2], scsi_bufflen(cp), rsp_info_len,
                    resid_len, fw_resid_len));
 
index 800ea926975236214c2846e4aa8b18ad12ebd56c..1830e6e973155684234710e129e564f82176ce2d 100644 (file)
@@ -160,6 +160,11 @@ MODULE_PARM_DESC(ql2xtargetreset,
                 "Enable target reset."
                 "Default is 1 - use hw defaults.");
 
+int ql2xgffidenable;
+module_param(ql2xgffidenable, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xgffidenable,
+               "Enables GFF_ID checks of port type. "
+               "Default is 0 - Do not use GFF_ID information.");
 
 int ql2xasynctmfenable;
 module_param(ql2xasynctmfenable, int, S_IRUGO|S_IRUSR);
@@ -255,6 +260,7 @@ static void qla2x00_rst_aen(scsi_qla_host_t *);
 
 static int qla2x00_mem_alloc(struct qla_hw_data *, uint16_t, uint16_t,
        struct req_que **, struct rsp_que **);
+static void qla2x00_free_fw_dump(struct qla_hw_data *);
 static void qla2x00_mem_free(struct qla_hw_data *);
 static void qla2x00_sp_free_dma(srb_t *);
 
@@ -539,6 +545,7 @@ qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
        srb_t *sp;
        int rval;
 
+       spin_unlock_irq(vha->host->host_lock);
        if (ha->flags.eeh_busy) {
                if (ha->flags.pci_channel_io_perm_failure)
                        cmd->result = DID_NO_CONNECT << 16;
@@ -553,10 +560,6 @@ qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
                goto qc24_fail_command;
        }
 
-       /* Close window on fcport/rport state-transitioning. */
-       if (fcport->drport)
-               goto qc24_target_busy;
-
        if (!vha->flags.difdix_supported &&
                scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) {
                        DEBUG2(qla_printk(KERN_ERR, ha,
@@ -567,15 +570,14 @@ qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
        }
        if (atomic_read(&fcport->state) != FCS_ONLINE) {
                if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
-                   atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
+                       atomic_read(&fcport->state) == FCS_DEVICE_LOST ||
+                       atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
                        cmd->result = DID_NO_CONNECT << 16;
                        goto qc24_fail_command;
                }
                goto qc24_target_busy;
        }
 
-       spin_unlock_irq(vha->host->host_lock);
-
        sp = qla2x00_get_new_sp(base_vha, fcport, cmd, done);
        if (!sp)
                goto qc24_host_busy_lock;
@@ -597,9 +599,11 @@ qc24_host_busy_lock:
        return SCSI_MLQUEUE_HOST_BUSY;
 
 qc24_target_busy:
+       spin_lock_irq(vha->host->host_lock);
        return SCSI_MLQUEUE_TARGET_BUSY;
 
 qc24_fail_command:
+       spin_lock_irq(vha->host->host_lock);
        done(cmd);
 
        return 0;
@@ -824,81 +828,58 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
 {
        scsi_qla_host_t *vha = shost_priv(cmd->device->host);
        srb_t *sp;
-       int ret, i;
+       int ret;
        unsigned int id, lun;
-       unsigned long serial;
        unsigned long flags;
        int wait = 0;
        struct qla_hw_data *ha = vha->hw;
-       struct req_que *req = vha->req;
-       srb_t *spt;
-       int got_ref = 0;
 
        fc_block_scsi_eh(cmd);
 
        if (!CMD_SP(cmd))
                return SUCCESS;
 
-       ret = SUCCESS;
-
        id = cmd->device->id;
        lun = cmd->device->lun;
-       serial = cmd->serial_number;
-       spt = (srb_t *) CMD_SP(cmd);
-       if (!spt)
-               return SUCCESS;
 
-       /* Check active list for command command. */
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
-               sp = req->outstanding_cmds[i];
-
-               if (sp == NULL)
-                       continue;
-               if ((sp->ctx) && !(sp->flags & SRB_FCP_CMND_DMA_VALID) &&
-                   !IS_PROT_IO(sp))
-                       continue;
-               if (sp->cmd != cmd)
-                       continue;
+       sp = (srb_t *) CMD_SP(cmd);
+       if (!sp) {
+               spin_unlock_irqrestore(&ha->hardware_lock, flags);
+               return SUCCESS;
+       }
 
-               DEBUG2(printk("%s(%ld): aborting sp %p from RISC."
-               " pid=%ld.\n", __func__, vha->host_no, sp, serial));
+       DEBUG2(printk("%s(%ld): aborting sp %p from RISC.",
+           __func__, vha->host_no, sp));
 
-               /* Get a reference to the sp and drop the lock.*/
-               sp_get(sp);
-               got_ref++;
+       /* Get a reference to the sp and drop the lock.*/
+       sp_get(sp);
 
-               spin_unlock_irqrestore(&ha->hardware_lock, flags);
-               if (ha->isp_ops->abort_command(sp)) {
-                       DEBUG2(printk("%s(%ld): abort_command "
-                       "mbx failed.\n", __func__, vha->host_no));
-                       ret = FAILED;
-               } else {
-                       DEBUG3(printk("%s(%ld): abort_command "
-                       "mbx success.\n", __func__, vha->host_no));
-                       wait = 1;
-               }
-               spin_lock_irqsave(&ha->hardware_lock, flags);
-               break;
-       }
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
+       if (ha->isp_ops->abort_command(sp)) {
+               DEBUG2(printk("%s(%ld): abort_command "
+               "mbx failed.\n", __func__, vha->host_no));
+               ret = FAILED;
+       } else {
+               DEBUG3(printk("%s(%ld): abort_command "
+               "mbx success.\n", __func__, vha->host_no));
+               wait = 1;
+       }
+       qla2x00_sp_compl(ha, sp);
 
        /* Wait for the command to be returned. */
        if (wait) {
                if (qla2x00_eh_wait_on_command(cmd) != QLA_SUCCESS) {
                        qla_printk(KERN_ERR, ha,
-                           "scsi(%ld:%d:%d): Abort handler timed out -- %lx "
-                           "%x.\n", vha->host_no, id, lun, serial, ret);
+                           "scsi(%ld:%d:%d): Abort handler timed out -- %x.\n",
+                           vha->host_no, id, lun, ret);
                        ret = FAILED;
                }
        }
 
-       if (got_ref)
-               qla2x00_sp_compl(ha, sp);
-
        qla_printk(KERN_INFO, ha,
-           "scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n",
-           vha->host_no, id, lun, wait, serial, ret);
+           "scsi(%ld:%d:%d): Abort command issued -- %d %x.\n",
+           vha->host_no, id, lun, wait, ret);
 
        return ret;
 }
@@ -1043,13 +1024,11 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
        int ret = FAILED;
        unsigned int id, lun;
-       unsigned long serial;
 
        fc_block_scsi_eh(cmd);
 
        id = cmd->device->id;
        lun = cmd->device->lun;
-       serial = cmd->serial_number;
 
        if (!fcport)
                return ret;
@@ -1104,14 +1083,12 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
        struct qla_hw_data *ha = vha->hw;
        int ret = FAILED;
        unsigned int id, lun;
-       unsigned long serial;
        scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
 
        fc_block_scsi_eh(cmd);
 
        id = cmd->device->id;
        lun = cmd->device->lun;
-       serial = cmd->serial_number;
 
        if (!fcport)
                return ret;
@@ -1974,6 +1951,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        ha->bars = bars;
        ha->mem_only = mem_only;
        spin_lock_init(&ha->hardware_lock);
+       spin_lock_init(&ha->vport_slock);
 
        /* Set ISP-type information. */
        qla2x00_set_isp_flags(ha);
@@ -2341,6 +2319,42 @@ probe_out:
        return ret;
 }
 
+static void
+qla2x00_shutdown(struct pci_dev *pdev)
+{
+       scsi_qla_host_t *vha;
+       struct qla_hw_data  *ha;
+
+       vha = pci_get_drvdata(pdev);
+       ha = vha->hw;
+
+       /* Turn-off FCE trace */
+       if (ha->flags.fce_enabled) {
+               qla2x00_disable_fce_trace(vha, NULL, NULL);
+               ha->flags.fce_enabled = 0;
+       }
+
+       /* Turn-off EFT trace */
+       if (ha->eft)
+               qla2x00_disable_eft_trace(vha);
+
+       /* Stop currently executing firmware. */
+       qla2x00_try_to_stop_firmware(vha);
+
+       /* Turn adapter off line */
+       vha->flags.online = 0;
+
+       /* turn-off interrupts on the card */
+       if (ha->interrupts_on) {
+               vha->flags.init_done = 0;
+               ha->isp_ops->disable_intrs(ha);
+       }
+
+       qla2x00_free_irqs(vha);
+
+       qla2x00_free_fw_dump(ha);
+}
+
 static void
 qla2x00_remove_one(struct pci_dev *pdev)
 {
@@ -2597,12 +2611,12 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer)
                if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
                        continue;
                if (atomic_read(&fcport->state) == FCS_ONLINE) {
+                       atomic_set(&fcport->state, FCS_DEVICE_LOST);
                        if (defer)
                                qla2x00_schedule_rport_del(vha, fcport, defer);
                        else if (vha->vp_idx == fcport->vp_idx)
                                qla2x00_schedule_rport_del(vha, fcport, defer);
                }
-               atomic_set(&fcport->state, FCS_DEVICE_LOST);
        }
 }
 
@@ -2830,28 +2844,48 @@ fail:
 }
 
 /*
-* qla2x00_mem_free
-*      Frees all adapter allocated memory.
+* qla2x00_free_fw_dump
+*      Frees fw dump stuff.
 *
 * Input:
-*      ha = adapter block pointer.
+*      ha = adapter block pointer.
 */
 static void
-qla2x00_mem_free(struct qla_hw_data *ha)
+qla2x00_free_fw_dump(struct qla_hw_data *ha)
 {
-       if (ha->srb_mempool)
-               mempool_destroy(ha->srb_mempool);
-
        if (ha->fce)
                dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
-               ha->fce_dma);
+                   ha->fce_dma);
 
        if (ha->fw_dump) {
                if (ha->eft)
                        dma_free_coherent(&ha->pdev->dev,
-                       ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma);
+                           ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma);
                vfree(ha->fw_dump);
        }
+       ha->fce = NULL;
+       ha->fce_dma = 0;
+       ha->eft = NULL;
+       ha->eft_dma = 0;
+       ha->fw_dump = NULL;
+       ha->fw_dumped = 0;
+       ha->fw_dump_reading = 0;
+}
+
+/*
+* qla2x00_mem_free
+*      Frees all adapter allocated memory.
+*
+* Input:
+*      ha = adapter block pointer.
+*/
+static void
+qla2x00_mem_free(struct qla_hw_data *ha)
+{
+       qla2x00_free_fw_dump(ha);
+
+       if (ha->srb_mempool)
+               mempool_destroy(ha->srb_mempool);
 
        if (ha->dcbx_tlv)
                dma_free_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE,
@@ -2925,8 +2959,6 @@ qla2x00_mem_free(struct qla_hw_data *ha)
 
        ha->srb_mempool = NULL;
        ha->ctx_mempool = NULL;
-       ha->eft = NULL;
-       ha->eft_dma = 0;
        ha->sns_cmd = NULL;
        ha->sns_cmd_dma = 0;
        ha->ct_sns = NULL;
@@ -2946,10 +2978,6 @@ qla2x00_mem_free(struct qla_hw_data *ha)
 
        ha->gid_list = NULL;
        ha->gid_list_dma = 0;
-
-       ha->fw_dump = NULL;
-       ha->fw_dumped = 0;
-       ha->fw_dump_reading = 0;
 }
 
 struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
@@ -3547,11 +3575,9 @@ void
 qla2x00_timer(scsi_qla_host_t *vha)
 {
        unsigned long   cpu_flags = 0;
-       fc_port_t       *fcport;
        int             start_dpc = 0;
        int             index;
        srb_t           *sp;
-       int             t;
        uint16_t        w;
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req;
@@ -3567,34 +3593,6 @@ qla2x00_timer(scsi_qla_host_t *vha)
        /* Hardware read to raise pending EEH errors during mailbox waits. */
        if (!pci_channel_offline(ha->pdev))
                pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
-       /*
-        * Ports - Port down timer.
-        *
-        * Whenever, a port is in the LOST state we start decrementing its port
-        * down timer every second until it reaches zero. Once  it reaches zero
-        * the port it marked DEAD.
-        */
-       t = 0;
-       list_for_each_entry(fcport, &vha->vp_fcports, list) {
-               if (fcport->port_type != FCT_TARGET)
-                       continue;
-
-               if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
-
-                       if (atomic_read(&fcport->port_down_timer) == 0)
-                               continue;
-
-                       if (atomic_dec_and_test(&fcport->port_down_timer) != 0)
-                               atomic_set(&fcport->state, FCS_DEVICE_DEAD);
-
-                       DEBUG(printk("scsi(%ld): fcport-%d - port retry count: "
-                           "%d remaining\n",
-                           vha->host_no,
-                           t, atomic_read(&fcport->port_down_timer)));
-               }
-               t++;
-       } /* End of for fcport  */
-
 
        /* Loop down handler. */
        if (atomic_read(&vha->loop_down_timer) > 0 &&
@@ -4079,6 +4077,7 @@ static struct pci_driver qla2xxx_pci_driver = {
        .id_table       = qla2xxx_pci_tbl,
        .probe          = qla2x00_probe_one,
        .remove         = qla2x00_remove_one,
+       .shutdown       = qla2x00_shutdown,
        .err_handler    = &qla2xxx_err_handler,
 };
 
index cbceb0ebabf7c41888ec091ab77f61e1c9b20f48..edcf048215dd18326181a8cdca07acf3198b3cb3 100644 (file)
@@ -30,3 +30,104 @@ void qla4xxx_dump_buffer(void *b, uint32_t size)
        printk(KERN_INFO "\n");
 }
 
+void qla4xxx_dump_registers(struct scsi_qla_host *ha)
+{
+       uint8_t i;
+
+       if (is_qla8022(ha)) {
+               for (i = 1; i < MBOX_REG_COUNT; i++)
+                       printk(KERN_INFO "mailbox[%d]     = 0x%08X\n",
+                           i, readl(&ha->qla4_8xxx_reg->mailbox_in[i]));
+               return;
+       }
+
+       for (i = 0; i < MBOX_REG_COUNT; i++) {
+               printk(KERN_INFO "0x%02X mailbox[%d]      = 0x%08X\n",
+                   (uint8_t) offsetof(struct isp_reg, mailbox[i]), i,
+                   readw(&ha->reg->mailbox[i]));
+       }
+
+       printk(KERN_INFO "0x%02X flash_address            = 0x%08X\n",
+           (uint8_t) offsetof(struct isp_reg, flash_address),
+           readw(&ha->reg->flash_address));
+       printk(KERN_INFO "0x%02X flash_data               = 0x%08X\n",
+           (uint8_t) offsetof(struct isp_reg, flash_data),
+           readw(&ha->reg->flash_data));
+       printk(KERN_INFO "0x%02X ctrl_status              = 0x%08X\n",
+           (uint8_t) offsetof(struct isp_reg, ctrl_status),
+           readw(&ha->reg->ctrl_status));
+
+       if (is_qla4010(ha)) {
+               printk(KERN_INFO "0x%02X nvram            = 0x%08X\n",
+                   (uint8_t) offsetof(struct isp_reg, u1.isp4010.nvram),
+                   readw(&ha->reg->u1.isp4010.nvram));
+       } else if (is_qla4022(ha) | is_qla4032(ha)) {
+               printk(KERN_INFO "0x%02X intr_mask        = 0x%08X\n",
+                   (uint8_t) offsetof(struct isp_reg, u1.isp4022.intr_mask),
+                   readw(&ha->reg->u1.isp4022.intr_mask));
+               printk(KERN_INFO "0x%02X nvram            = 0x%08X\n",
+                   (uint8_t) offsetof(struct isp_reg, u1.isp4022.nvram),
+                   readw(&ha->reg->u1.isp4022.nvram));
+               printk(KERN_INFO "0x%02X semaphore        = 0x%08X\n",
+                   (uint8_t) offsetof(struct isp_reg, u1.isp4022.semaphore),
+                   readw(&ha->reg->u1.isp4022.semaphore));
+       }
+       printk(KERN_INFO "0x%02X req_q_in                 = 0x%08X\n",
+           (uint8_t) offsetof(struct isp_reg, req_q_in),
+           readw(&ha->reg->req_q_in));
+       printk(KERN_INFO "0x%02X rsp_q_out                = 0x%08X\n",
+           (uint8_t) offsetof(struct isp_reg, rsp_q_out),
+           readw(&ha->reg->rsp_q_out));
+
+       if (is_qla4010(ha)) {
+               printk(KERN_INFO "0x%02X ext_hw_conf      = 0x%08X\n",
+                   (uint8_t) offsetof(struct isp_reg, u2.isp4010.ext_hw_conf),
+                   readw(&ha->reg->u2.isp4010.ext_hw_conf));
+               printk(KERN_INFO "0x%02X port_ctrl        = 0x%08X\n",
+                   (uint8_t) offsetof(struct isp_reg, u2.isp4010.port_ctrl),
+                   readw(&ha->reg->u2.isp4010.port_ctrl));
+               printk(KERN_INFO "0x%02X port_status      = 0x%08X\n",
+                   (uint8_t) offsetof(struct isp_reg, u2.isp4010.port_status),
+                   readw(&ha->reg->u2.isp4010.port_status));
+               printk(KERN_INFO "0x%02X req_q_out        = 0x%08X\n",
+                   (uint8_t) offsetof(struct isp_reg, u2.isp4010.req_q_out),
+                   readw(&ha->reg->u2.isp4010.req_q_out));
+               printk(KERN_INFO "0x%02X gp_out           = 0x%08X\n",
+                   (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_out),
+                   readw(&ha->reg->u2.isp4010.gp_out));
+               printk(KERN_INFO "0x%02X gp_in            = 0x%08X\n",
+                   (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_in),
+                   readw(&ha->reg->u2.isp4010.gp_in));
+               printk(KERN_INFO "0x%02X port_err_status  = 0x%08X\n", (uint8_t)
+                   offsetof(struct isp_reg, u2.isp4010.port_err_status),
+                   readw(&ha->reg->u2.isp4010.port_err_status));
+       } else if (is_qla4022(ha) | is_qla4032(ha)) {
+               printk(KERN_INFO "Page 0 Registers:\n");
+               printk(KERN_INFO "0x%02X ext_hw_conf      = 0x%08X\n", (uint8_t)
+                   offsetof(struct isp_reg, u2.isp4022.p0.ext_hw_conf),
+                   readw(&ha->reg->u2.isp4022.p0.ext_hw_conf));
+               printk(KERN_INFO "0x%02X port_ctrl        = 0x%08X\n", (uint8_t)
+                   offsetof(struct isp_reg, u2.isp4022.p0.port_ctrl),
+                   readw(&ha->reg->u2.isp4022.p0.port_ctrl));
+               printk(KERN_INFO "0x%02X port_status      = 0x%08X\n", (uint8_t)
+                   offsetof(struct isp_reg, u2.isp4022.p0.port_status),
+                   readw(&ha->reg->u2.isp4022.p0.port_status));
+               printk(KERN_INFO "0x%02X gp_out           = 0x%08X\n",
+                   (uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_out),
+                   readw(&ha->reg->u2.isp4022.p0.gp_out));
+               printk(KERN_INFO "0x%02X gp_in            = 0x%08X\n",
+                   (uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_in),
+                   readw(&ha->reg->u2.isp4022.p0.gp_in));
+               printk(KERN_INFO "0x%02X port_err_status  = 0x%08X\n", (uint8_t)
+                   offsetof(struct isp_reg, u2.isp4022.p0.port_err_status),
+                   readw(&ha->reg->u2.isp4022.p0.port_err_status));
+               printk(KERN_INFO "Page 1 Registers:\n");
+               writel(HOST_MEM_CFG_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
+                   &ha->reg->ctrl_status);
+               printk(KERN_INFO "0x%02X req_q_out        = 0x%08X\n",
+                   (uint8_t) offsetof(struct isp_reg, u2.isp4022.p1.req_q_out),
+                   readw(&ha->reg->u2.isp4022.p1.req_q_out));
+               writel(PORT_CTRL_STAT_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
+                   &ha->reg->ctrl_status);
+       }
+}
index 9dc0a6616edd566656154413a96f41043e886447..0f3bfc3da5cf6670287393bb4ca64baee59db2e4 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
+#include <linux/aer.h>
 
 #include <net/tcp.h>
 #include <scsi/scsi.h>
 #include "ql4_dbg.h"
 #include "ql4_nx.h"
 
-#if defined(CONFIG_PCIEAER)
-#include <linux/aer.h>
-#else
-/* AER releated */
-static inline int pci_enable_pcie_error_reporting(struct pci_dev *dev)
-{
-       return -EINVAL;
-}
-static inline int pci_disable_pcie_error_reporting(struct pci_dev *dev)
-{
-       return -EINVAL;
-}
-static inline int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
-{
-       return -EINVAL;
-}
-#endif
-
 #ifndef PCI_DEVICE_ID_QLOGIC_ISP4010
 #define PCI_DEVICE_ID_QLOGIC_ISP4010   0x4010
 #endif
@@ -179,6 +162,7 @@ static inline int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
 #define IOCB_TOV_MARGIN                        10
 #define RELOGIN_TOV                    18
 #define ISNS_DEREG_TOV                 5
+#define HBA_ONLINE_TOV                 30
 
 #define MAX_RESET_HA_RETRIES           2
 
index 0336c6db8cb3b338a15bf42608dcdfc1c12c8bfd..5e757d7fff7dc4eb0ae23d01ec93c4b6550d1ce6 100644 (file)
@@ -416,6 +416,8 @@ struct qla_flt_region {
 #define MBOX_ASTS_IPV6_ND_PREFIX_IGNORED       0x802C
 #define MBOX_ASTS_IPV6_LCL_PREFIX_IGNORED      0x802D
 #define MBOX_ASTS_ICMPV6_ERROR_MSG_RCVD                0x802E
+#define MBOX_ASTS_TXSCVR_INSERTED              0x8130
+#define MBOX_ASTS_TXSCVR_REMOVED               0x8131
 
 #define ISNS_EVENT_DATA_RECEIVED               0x0000
 #define ISNS_EVENT_CONNECTION_OPENED           0x0001
@@ -446,6 +448,7 @@ struct addr_ctrl_blk {
 #define         FWOPT_SESSION_MODE               0x0040
 #define         FWOPT_INITIATOR_MODE             0x0020
 #define         FWOPT_TARGET_MODE                0x0010
+#define         FWOPT_ENABLE_CRBDB               0x8000
 
        uint16_t exec_throttle; /* 04-05 */
        uint8_t zio_count;      /* 06 */
index 95a26fb1626c8c21af2473cc02c75fa654de08ce..6575a47501e57667f3f7c8dc2cae73c7c7fb5876 100644 (file)
@@ -94,6 +94,7 @@ void qla4xxx_process_response_queue(struct scsi_qla_host *ha);
 void qla4xxx_wake_dpc(struct scsi_qla_host *ha);
 void qla4xxx_get_conn_event_log(struct scsi_qla_host *ha);
 void qla4xxx_mailbox_premature_completion(struct scsi_qla_host *ha);
+void qla4xxx_dump_registers(struct scsi_qla_host *ha);
 
 void qla4_8xxx_pci_config(struct scsi_qla_host *);
 int qla4_8xxx_iospace_config(struct scsi_qla_host *ha);
index 4c9be77ee70b81a21a9bda19cd8116b3352bed98..dc01fa3da5d11be799f2c826bc324424e2bd3b76 100644 (file)
@@ -1207,8 +1207,8 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)
                        break;
 
                DEBUG2(printk(KERN_INFO "scsi%ld: %s: Waiting for boot "
-                             "firmware to complete... ctrl_sts=0x%x\n",
-                             ha->host_no, __func__, ctrl_status));
+                   "firmware to complete... ctrl_sts=0x%x, remaining=%ld\n",
+                   ha->host_no, __func__, ctrl_status, max_wait_time));
 
                msleep_interruptible(250);
        } while (!time_after_eq(jiffies, max_wait_time));
@@ -1459,6 +1459,12 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
 exit_init_online:
        set_bit(AF_ONLINE, &ha->flags);
 exit_init_hba:
+       if (is_qla8022(ha) && (status == QLA_ERROR)) {
+               /* Since interrupts are registered in start_firmware for
+                * 82xx, release them here if initialize_adapter fails */
+               qla4xxx_free_irqs(ha);
+       }
+
        DEBUG2(printk("scsi%ld: initialize adapter: %s\n", ha->host_no,
            status == QLA_ERROR ? "FAILED" : "SUCCEDED"));
        return status;
index 4ef9ba112ee87ecd55e4815a6572db9d9bf43106..5ae49fd8784639c8802e24c8ce210fd0f9cf1ee0 100644 (file)
@@ -202,19 +202,11 @@ static void qla4xxx_build_scsi_iocbs(struct srb *srb,
 void qla4_8xxx_queue_iocb(struct scsi_qla_host *ha)
 {
        uint32_t dbval = 0;
-       unsigned long wtime;
 
        dbval = 0x14 | (ha->func_num << 5);
        dbval = dbval | (0 << 8) | (ha->request_in << 16);
-       writel(dbval, (unsigned long __iomem *)ha->nx_db_wr_ptr);
-       wmb();
 
-       wtime = jiffies + (2 * HZ);
-       while (readl((void __iomem *)ha->nx_db_rd_ptr) != dbval &&
-           !time_after_eq(jiffies, wtime)) {
-               writel(dbval, (unsigned long __iomem *)ha->nx_db_wr_ptr);
-               wmb();
-       }
+       qla4_8xxx_wr_32(ha, ha->nx_db_wr_ptr, ha->request_in);
 }
 
 /**
index 2a1ab63f3eb0165de7a147be1eeef222c0b03e9a..7c33fd5943d50315a22ac5ff64de69799fe795a2 100644 (file)
@@ -72,7 +72,7 @@ qla4xxx_status_cont_entry(struct scsi_qla_host *ha,
 {
        struct srb *srb = ha->status_srb;
        struct scsi_cmnd *cmd;
-       uint8_t sense_len;
+       uint16_t sense_len;
 
        if (srb == NULL)
                return;
@@ -487,6 +487,8 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
                case MBOX_ASTS_SYSTEM_ERROR:
                        /* Log Mailbox registers */
                        ql4_printk(KERN_INFO, ha, "%s: System Err\n", __func__);
+                       qla4xxx_dump_registers(ha);
+
                        if (ql4xdontresethba) {
                                DEBUG2(printk("scsi%ld: %s:Don't Reset HBA\n",
                                    ha->host_no, __func__));
@@ -621,6 +623,18 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
                        }
                        break;
 
+               case MBOX_ASTS_TXSCVR_INSERTED:
+                       DEBUG2(printk(KERN_WARNING
+                           "scsi%ld: AEN %04x Transceiver"
+                           " inserted\n",  ha->host_no, mbox_sts[0]));
+                       break;
+
+               case MBOX_ASTS_TXSCVR_REMOVED:
+                       DEBUG2(printk(KERN_WARNING
+                           "scsi%ld: AEN %04x Transceiver"
+                           " removed\n",  ha->host_no, mbox_sts[0]));
+                       break;
+
                default:
                        DEBUG2(printk(KERN_WARNING
                                      "scsi%ld: AEN %04x UNKNOWN\n",
index 90021704d8cac0e37a30c2b788e8f40a17875229..2d2f9c879bfd57994366e050f9a82bc2541a4030 100644 (file)
@@ -299,6 +299,10 @@ qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
 {
        memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT);
        memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT);
+
+       if (is_qla8022(ha))
+               qla4_8xxx_wr_32(ha, ha->nx_db_wr_ptr, 0);
+
        mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE;
        mbox_cmd[1] = 0;
        mbox_cmd[2] = LSDW(init_fw_cb_dma);
@@ -472,6 +476,11 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
        init_fw_cb->fw_options |=
                __constant_cpu_to_le16(FWOPT_SESSION_MODE |
                                       FWOPT_INITIATOR_MODE);
+
+       if (is_qla8022(ha))
+               init_fw_cb->fw_options |=
+                   __constant_cpu_to_le16(FWOPT_ENABLE_CRBDB);
+
        init_fw_cb->fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE);
 
        if (qla4xxx_set_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma)
@@ -592,7 +601,7 @@ int qla4xxx_get_firmware_status(struct scsi_qla_host * ha)
        }
 
        ql4_printk(KERN_INFO, ha, "%ld firmare IOCBs available (%d).\n",
-           ha->host_no, mbox_cmd[2]);
+           ha->host_no, mbox_sts[2]);
 
        return QLA_SUCCESS;
 }
index 449256f2c5f8dc213226e2a81fa44e85eab18990..474b10d713647ea8aafde7a9057a49450bcf99e9 100644 (file)
@@ -839,8 +839,11 @@ qla4_8xxx_rom_lock(struct scsi_qla_host *ha)
                done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_LOCK));
                if (done == 1)
                        break;
-               if (timeout >= qla4_8xxx_rom_lock_timeout)
+               if (timeout >= qla4_8xxx_rom_lock_timeout) {
+                       ql4_printk(KERN_WARNING, ha,
+                           "%s: Failed to acquire rom lock", __func__);
                        return -1;
+               }
 
                timeout++;
 
@@ -1078,21 +1081,6 @@ qla4_8xxx_pinit_from_rom(struct scsi_qla_host *ha, int verbose)
        return 0;
 }
 
-static int qla4_8xxx_check_for_bad_spd(struct scsi_qla_host *ha)
-{
-       u32 val = 0;
-       val = qla4_8xxx_rd_32(ha, BOOT_LOADER_DIMM_STATUS) ;
-       val &= QLA82XX_BOOT_LOADER_MN_ISSUE;
-       if (val & QLA82XX_PEG_TUNE_MN_SPD_ZEROED) {
-               printk("Memory DIMM SPD not programmed.  Assumed valid.\n");
-               return 1;
-       } else if (val) {
-               printk("Memory DIMM type incorrect.  Info:%08X.\n", val);
-               return 2;
-       }
-       return 0;
-}
-
 static int
 qla4_8xxx_load_from_flash(struct scsi_qla_host *ha, uint32_t image_start)
 {
@@ -1377,8 +1365,6 @@ static int qla4_8xxx_cmdpeg_ready(struct scsi_qla_host *ha, int pegtune_val)
 
                } while (--retries);
 
-               qla4_8xxx_check_for_bad_spd(ha);
-
                if (!retries) {
                        pegtune_val = qla4_8xxx_rd_32(ha,
                                QLA82XX_ROMUSB_GLB_PEGTUNE_DONE);
@@ -1540,14 +1526,31 @@ qla4_8xxx_try_start_fw(struct scsi_qla_host *ha)
        ql4_printk(KERN_INFO, ha,
            "FW: Attempting to load firmware from flash...\n");
        rval = qla4_8xxx_start_firmware(ha, ha->hw.flt_region_fw);
-       if (rval == QLA_SUCCESS)
-               return rval;
 
-       ql4_printk(KERN_ERR, ha, "FW: Load firmware from flash FAILED...\n");
+       if (rval != QLA_SUCCESS) {
+               ql4_printk(KERN_ERR, ha, "FW: Load firmware from flash"
+                   " FAILED...\n");
+               return rval;
+       }
 
        return rval;
 }
 
+static void qla4_8xxx_rom_lock_recovery(struct scsi_qla_host *ha)
+{
+       if (qla4_8xxx_rom_lock(ha)) {
+               /* Someone else is holding the lock. */
+               dev_info(&ha->pdev->dev, "Resetting rom_lock\n");
+       }
+
+       /*
+        * Either we got the lock, or someone
+        * else died while holding it.
+        * In either case, unlock.
+        */
+       qla4_8xxx_rom_unlock(ha);
+}
+
 /**
  * qla4_8xxx_device_bootstrap - Initialize device, set DEV_READY, start fw
  * @ha: pointer to adapter structure
@@ -1557,11 +1560,12 @@ qla4_8xxx_try_start_fw(struct scsi_qla_host *ha)
 static int
 qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha)
 {
-       int rval, i, timeout;
+       int rval = QLA_ERROR;
+       int i, timeout;
        uint32_t old_count, count;
+       int need_reset = 0, peg_stuck = 1;
 
-       if (qla4_8xxx_need_reset(ha))
-               goto dev_initialize;
+       need_reset = qla4_8xxx_need_reset(ha);
 
        old_count = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
 
@@ -1570,12 +1574,30 @@ qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha)
                if (timeout) {
                        qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
                           QLA82XX_DEV_FAILED);
-                       return QLA_ERROR;
+                       return rval;
                }
 
                count = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
                if (count != old_count)
+                       peg_stuck = 0;
+       }
+
+       if (need_reset) {
+               /* We are trying to perform a recovery here. */
+               if (peg_stuck)
+                       qla4_8xxx_rom_lock_recovery(ha);
+               goto dev_initialize;
+       } else  {
+               /* Start of day for this ha context. */
+               if (peg_stuck) {
+                       /* Either we are the first or recovery in progress. */
+                       qla4_8xxx_rom_lock_recovery(ha);
+                       goto dev_initialize;
+               } else {
+                       /* Firmware already running. */
+                       rval = QLA_SUCCESS;
                        goto dev_ready;
+               }
        }
 
 dev_initialize:
@@ -1601,7 +1623,7 @@ dev_ready:
        ql4_printk(KERN_INFO, ha, "HW State: READY\n");
        qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_READY);
 
-       return QLA_SUCCESS;
+       return rval;
 }
 
 /**
@@ -1764,20 +1786,9 @@ int qla4_8xxx_load_risc(struct scsi_qla_host *ha)
        int retval;
        retval = qla4_8xxx_device_state_handler(ha);
 
-       if (retval == QLA_SUCCESS &&
-           !test_bit(AF_INIT_DONE, &ha->flags)) {
+       if (retval == QLA_SUCCESS && !test_bit(AF_INIT_DONE, &ha->flags))
                retval = qla4xxx_request_irqs(ha);
-               if (retval != QLA_SUCCESS) {
-                       ql4_printk(KERN_WARNING, ha,
-                           "Failed to reserve interrupt %d already in use.\n",
-                           ha->pdev->irq);
-               } else {
-                       set_bit(AF_IRQ_ATTACHED, &ha->flags);
-                       ha->host->irq = ha->pdev->irq;
-                       ql4_printk(KERN_INFO, ha, "%s: irq %d attached\n",
-                           __func__, ha->pdev->irq);
-               }
-       }
+
        return retval;
 }
 
index 931ad3f1e918c12b1289839d8ea9a8d556658475..ff689bf530071a1978fe85bce5e56082b2570e8b 100644 (file)
@@ -24,7 +24,6 @@
 
 #define CRB_CMDPEG_STATE               QLA82XX_REG(0x50)
 #define CRB_RCVPEG_STATE               QLA82XX_REG(0x13c)
-#define BOOT_LOADER_DIMM_STATUS                QLA82XX_REG(0x54)
 #define CRB_DMA_SHIFT                  QLA82XX_REG(0xcc)
 
 #define QLA82XX_HW_H0_CH_HUB_ADR       0x05
 # define QLA82XX_CAM_RAM_BASE  (QLA82XX_CRB_CAM + 0x02000)
 # define QLA82XX_CAM_RAM(reg)  (QLA82XX_CAM_RAM_BASE + (reg))
 
-#define QLA82XX_PEG_TUNE_MN_SPD_ZEROED 0x80000000
-#define QLA82XX_BOOT_LOADER_MN_ISSUE   0xff00ffff
 #define QLA82XX_PORT_MODE_ADDR         (QLA82XX_CAM_RAM(0x24))
 #define QLA82XX_PEG_HALT_STATUS1       (QLA82XX_CAM_RAM(0xa8))
 #define QLA82XX_PEG_HALT_STATUS2       (QLA82XX_CAM_RAM(0xac))
 #define QLA82XX_PEG_ALIVE_COUNTER      (QLA82XX_CAM_RAM(0xb0))
+#define QLA82XX_CAM_RAM_DB1            (QLA82XX_CAM_RAM(0x1b0))
+#define QLA82XX_CAM_RAM_DB2            (QLA82XX_CAM_RAM(0x1b4))
 
 #define HALT_STATUS_UNRECOVERABLE      0x80000000
 #define HALT_STATUS_RECOVERABLE                0x40000000
index 370d40ff15296ff8c1c19f3294a011ba94450b75..f4cd846abf6dcf77dc7d6bd7a855437ba6a1868f 100644 (file)
@@ -167,8 +167,6 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session)
                              "of (%d) secs exhausted, marking device DEAD.\n",
                              ha->host_no, __func__, ddb_entry->fw_ddb_index,
                              QL4_SESS_RECOVERY_TMO));
-
-               qla4xxx_wake_dpc(ha);
        }
 }
 
@@ -573,10 +571,6 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha)
                if (ha->nx_pcibase)
                        iounmap(
                            (struct device_reg_82xx __iomem *)ha->nx_pcibase);
-
-               if (ha->nx_db_wr_ptr)
-                       iounmap(
-                           (struct device_reg_82xx __iomem *)ha->nx_db_wr_ptr);
        } else if (ha->reg)
                iounmap(ha->reg);
        pci_release_regions(ha->pdev);
@@ -692,7 +686,9 @@ static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
                        qla4xxx_wake_dpc(ha);
                        qla4xxx_mailbox_premature_completion(ha);
                }
-       }
+       } else
+               ha->seconds_since_last_heartbeat = 0;
+
        ha->fw_heartbeat_counter = fw_heartbeat_counter;
 }
 
@@ -885,7 +881,13 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
                /* Find a command that hasn't completed. */
                for (index = 0; index < ha->host->can_queue; index++) {
                        cmd = scsi_host_find_tag(ha->host, index);
-                       if (cmd != NULL)
+                       /*
+                        * We cannot just check if the index is valid,
+                        * becase if we are run from the scsi eh, then
+                        * the scsi/block layer is going to prevent
+                        * the tag from being released.
+                        */
+                       if (cmd != NULL && CMD_SP(cmd))
                                break;
                }
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -937,11 +939,14 @@ int qla4xxx_soft_reset(struct scsi_qla_host *ha)
 {
        uint32_t max_wait_time;
        unsigned long flags = 0;
-       int status = QLA_ERROR;
+       int status;
        uint32_t ctrl_status;
 
-       qla4xxx_hw_reset(ha);
+       status = qla4xxx_hw_reset(ha);
+       if (status != QLA_SUCCESS)
+               return status;
 
+       status = QLA_ERROR;
        /* Wait until the Network Reset Intr bit is cleared */
        max_wait_time = RESET_INTR_TOV;
        do {
@@ -1101,7 +1106,8 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
                    ha->host_no, __func__));
                status = ha->isp_ops->reset_firmware(ha);
                if (status == QLA_SUCCESS) {
-                       qla4xxx_cmd_wait(ha);
+                       if (!test_bit(AF_FW_RECOVERY, &ha->flags))
+                               qla4xxx_cmd_wait(ha);
                        ha->isp_ops->disable_intrs(ha);
                        qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
                        qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
@@ -1118,7 +1124,8 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
         * or if stop_firmware fails for ISP-82xx.
         * This is the default case for ISP-4xxx */
        if (!is_qla8022(ha) || reset_chip) {
-               qla4xxx_cmd_wait(ha);
+               if (!test_bit(AF_FW_RECOVERY, &ha->flags))
+                       qla4xxx_cmd_wait(ha);
                qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
                qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
                DEBUG2(ql4_printk(KERN_INFO, ha,
@@ -1471,24 +1478,10 @@ int qla4_8xxx_iospace_config(struct scsi_qla_host *ha)
        db_base = pci_resource_start(pdev, 4);  /* doorbell is on bar 4 */
        db_len = pci_resource_len(pdev, 4);
 
-       /* mapping of doorbell write pointer */
-       ha->nx_db_wr_ptr = (unsigned long)ioremap(db_base +
-           (ha->pdev->devfn << 12), 4);
-       if (!ha->nx_db_wr_ptr) {
-               printk(KERN_ERR
-                   "cannot remap MMIO doorbell-write (%s), aborting\n",
-                   pci_name(pdev));
-               goto iospace_error_exit;
-       }
-       /* mapping of doorbell read pointer */
-       ha->nx_db_rd_ptr = (uint8_t *) ha->nx_pcibase + (512 * 1024) +
-           (ha->pdev->devfn * 8);
-       if (!ha->nx_db_rd_ptr)
-               printk(KERN_ERR
-                   "cannot remap MMIO doorbell-read (%s), aborting\n",
-                   pci_name(pdev));
-       return 0;
+       ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 :
+           QLA82XX_CAM_RAM_DB2);
 
+       return 0;
 iospace_error_exit:
        return -ENOMEM;
 }
@@ -1960,13 +1953,11 @@ static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
 {
        unsigned long wait_online;
 
-       wait_online = jiffies + (30 * HZ);
+       wait_online = jiffies + (HBA_ONLINE_TOV * HZ);
        while (time_before(jiffies, wait_online)) {
 
                if (adapter_up(ha))
                        return QLA_SUCCESS;
-               else if (ha->retry_reset_ha_cnt == 0)
-                       return QLA_ERROR;
 
                msleep(2000);
        }
@@ -2021,6 +2012,7 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
        unsigned int id = cmd->device->id;
        unsigned int lun = cmd->device->lun;
        unsigned long serial = cmd->serial_number;
+       unsigned long flags;
        struct srb *srb = NULL;
        int ret = SUCCESS;
        int wait = 0;
@@ -2029,12 +2021,14 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
            "scsi%ld:%d:%d: Abort command issued cmd=%p, pid=%ld\n",
            ha->host_no, id, lun, cmd, serial);
 
+       spin_lock_irqsave(&ha->hardware_lock, flags);
        srb = (struct srb *) CMD_SP(cmd);
-
-       if (!srb)
+       if (!srb) {
+               spin_unlock_irqrestore(&ha->hardware_lock, flags);
                return SUCCESS;
-
+       }
        kref_get(&srb->srb_ref);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) {
                DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n",
@@ -2267,6 +2261,8 @@ qla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
                qla4xxx_mailbox_premature_completion(ha);
                qla4xxx_free_irqs(ha);
                pci_disable_device(pdev);
+               /* Return back all IOs */
+               qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
                return PCI_ERS_RESULT_NEED_RESET;
        case pci_channel_io_perm_failure:
                set_bit(AF_EEH_BUSY, &ha->flags);
@@ -2290,17 +2286,13 @@ qla4xxx_pci_mmio_enabled(struct pci_dev *pdev)
        if (!is_aer_supported(ha))
                return PCI_ERS_RESULT_NONE;
 
-       if (test_bit(AF_FW_RECOVERY, &ha->flags)) {
-               ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: firmware hang  -- "
-                   "mmio_enabled\n", ha->host_no, __func__);
-               return PCI_ERS_RESULT_NEED_RESET;
-       } else
-               return PCI_ERS_RESULT_RECOVERED;
+       return PCI_ERS_RESULT_RECOVERED;
 }
 
-uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
+static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
 {
        uint32_t rval = QLA_ERROR;
+       uint32_t ret = 0;
        int fn;
        struct pci_dev *other_pdev = NULL;
 
@@ -2312,7 +2304,6 @@ uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
                clear_bit(AF_ONLINE, &ha->flags);
                qla4xxx_mark_all_devices_missing(ha);
                qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
-               qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
        }
 
        fn = PCI_FUNC(ha->pdev->devfn);
@@ -2375,7 +2366,16 @@ uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
                        /* Clear driver state register */
                        qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0);
                        qla4_8xxx_set_drv_active(ha);
-                       ha->isp_ops->enable_intrs(ha);
+                       ret = qla4xxx_request_irqs(ha);
+                       if (ret) {
+                               ql4_printk(KERN_WARNING, ha, "Failed to "
+                                   "reserve interrupt %d already in use.\n",
+                                   ha->pdev->irq);
+                               rval = QLA_ERROR;
+                       } else {
+                               ha->isp_ops->enable_intrs(ha);
+                               rval = QLA_SUCCESS;
+                       }
                }
                qla4_8xxx_idc_unlock(ha);
        } else {
@@ -2387,8 +2387,18 @@ uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
                        clear_bit(AF_FW_RECOVERY, &ha->flags);
                        rval = qla4xxx_initialize_adapter(ha,
                            PRESERVE_DDB_LIST);
-                       if (rval == QLA_SUCCESS)
-                               ha->isp_ops->enable_intrs(ha);
+                       if (rval == QLA_SUCCESS) {
+                               ret = qla4xxx_request_irqs(ha);
+                               if (ret) {
+                                       ql4_printk(KERN_WARNING, ha, "Failed to"
+                                           " reserve interrupt %d already in"
+                                           " use.\n", ha->pdev->irq);
+                                       rval = QLA_ERROR;
+                               } else {
+                                       ha->isp_ops->enable_intrs(ha);
+                                       rval = QLA_SUCCESS;
+                               }
+                       }
                        qla4_8xxx_idc_lock(ha);
                        qla4_8xxx_set_drv_active(ha);
                        qla4_8xxx_idc_unlock(ha);
@@ -2430,12 +2440,7 @@ qla4xxx_pci_slot_reset(struct pci_dev *pdev)
                goto exit_slot_reset;
        }
 
-       ret = qla4xxx_request_irqs(ha);
-       if (ret) {
-               ql4_printk(KERN_WARNING, ha, "Failed to reserve interrupt %d"
-                   " already in use.\n", pdev->irq);
-               goto exit_slot_reset;
-       }
+       ha->isp_ops->disable_intrs(ha);
 
        if (is_qla8022(ha)) {
                if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) {
index a77b973f2cbc607c60c510b8f1e58ae048fb3c42..9bfacf4ed1371f30a557ac99250feb8e2d3f0987 100644 (file)
@@ -5,4 +5,4 @@
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
 
-#define QLA4XXX_DRIVER_VERSION "5.02.00-k3"
+#define QLA4XXX_DRIVER_VERSION "5.02.00-k4"
index 8041fe1ab179c2c2e77386726b8082c05643b187..eafeeda6e1942b7deda691f940c0f10efddee390 100644 (file)
@@ -2438,7 +2438,8 @@ scsi_internal_device_unblock(struct scsi_device *sdev)
                sdev->sdev_state = SDEV_RUNNING;
        else if (sdev->sdev_state == SDEV_CREATED_BLOCK)
                sdev->sdev_state = SDEV_CREATED;
-       else
+       else if (sdev->sdev_state != SDEV_CANCEL &&
+                sdev->sdev_state != SDEV_OFFLINE)
                return -EINVAL;
 
        spin_lock_irqsave(q->queue_lock, flags);
index 20ad59dff730289dd3d05768574e8695ea407109..76ee2e784f75085660524fa35143804659735dbd 100644 (file)
@@ -964,10 +964,11 @@ static void __scsi_remove_target(struct scsi_target *starget)
        list_for_each_entry(sdev, &shost->__devices, siblings) {
                if (sdev->channel != starget->channel ||
                    sdev->id != starget->id ||
-                   sdev->sdev_state == SDEV_DEL)
+                   scsi_device_get(sdev))
                        continue;
                spin_unlock_irqrestore(shost->host_lock, flags);
                scsi_remove_device(sdev);
+               scsi_device_put(sdev);
                spin_lock_irqsave(shost->host_lock, flags);
                goto restart;
        }
index 57d1e3e1bd4478548f89ef9f3a472ee4418c71b3..b9ab3a590e4b4fd891865a1f9d3d5f3cb55d9dc5 100644 (file)
@@ -258,6 +258,28 @@ sd_show_protection_type(struct device *dev, struct device_attribute *attr,
        return snprintf(buf, 20, "%u\n", sdkp->protection_type);
 }
 
+static ssize_t
+sd_show_protection_mode(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct scsi_disk *sdkp = to_scsi_disk(dev);
+       struct scsi_device *sdp = sdkp->device;
+       unsigned int dif, dix;
+
+       dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type);
+       dix = scsi_host_dix_capable(sdp->host, sdkp->protection_type);
+
+       if (!dix && scsi_host_dix_capable(sdp->host, SD_DIF_TYPE0_PROTECTION)) {
+               dif = 0;
+               dix = 1;
+       }
+
+       if (!dif && !dix)
+               return snprintf(buf, 20, "none\n");
+
+       return snprintf(buf, 20, "%s%u\n", dix ? "dix" : "dif", dif);
+}
+
 static ssize_t
 sd_show_app_tag_own(struct device *dev, struct device_attribute *attr,
                    char *buf)
@@ -285,6 +307,7 @@ static struct device_attribute sd_disk_attrs[] = {
        __ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop,
               sd_store_manage_start_stop),
        __ATTR(protection_type, S_IRUGO, sd_show_protection_type, NULL),
+       __ATTR(protection_mode, S_IRUGO, sd_show_protection_mode, NULL),
        __ATTR(app_tag_own, S_IRUGO, sd_show_app_tag_own, NULL),
        __ATTR(thin_provisioning, S_IRUGO, sd_show_thin_provisioning, NULL),
        __ATTR_NULL,
index cbb38c5197fad67299f32a36792ab1fc5cdeec3e..3cd8ffbad5776dbcee289f1465022602e3897199 100644 (file)
@@ -324,6 +324,15 @@ int sr_drive_status(struct cdrom_device_info *cdi, int slot)
                        return CDS_NO_DISC;
        }
 
+       /*
+        * SK/ASC/ASCQ of 2/4/2 means "initialization required"
+        * Using CD_TRAY_OPEN results in an START_STOP_UNIT to close
+        * the tray, which resolves the initialization requirement.
+        */
+       if (scsi_sense_valid(&sshdr) && sshdr.sense_key == NOT_READY
+                       && sshdr.asc == 0x04 && sshdr.ascq == 0x02)
+               return CDS_TRAY_OPEN;
+
        /*
         * 0x04 is format in progress .. but there must be a disc present!
         */
index c856905bb3bdfc3105ac5eff30de5aad2160c265..fa62578fcd20f572dbd391b614e47f246250b978 100644 (file)
@@ -1411,11 +1411,12 @@ e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r)
                       CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1);
 #endif
 
-       info->rs485.flags = r->flags;
-       if (r->delay_rts_before_send >= 1000)
+       info->rs485 = *r;
+
+       /* Maximum delay before RTS equal to 1000 */
+       if (info->rs485.delay_rts_before_send >= 1000)
                info->rs485.delay_rts_before_send = 1000;
-       else
-               info->rs485.delay_rts_before_send = r->delay_rts_before_send;
+
 /*     printk("rts: on send = %i, after = %i, enabled = %i",
                    info->rs485.rts_on_send,
                    info->rs485.rts_after_sent,
@@ -3234,9 +3235,9 @@ rs_write(struct tty_struct *tty,
                e100_disable_rx(info);
                e100_enable_rx_irq(info);
 #endif
-
-               if (info->rs485.delay_rts_before_send > 0)
-                       msleep(info->rs485.delay_rts_before_send);
+               if ((info->rs485.flags & SER_RS485_RTS_BEFORE_SEND) &&
+                       (info->rs485.delay_rts_before_send > 0))
+                               msleep(info->rs485.delay_rts_before_send);
        }
 #endif /* CONFIG_ETRAX_RS485 */
 
@@ -3694,6 +3695,11 @@ rs_ioctl(struct tty_struct *tty, struct file * file,
 
                rs485data.delay_rts_before_send = rs485ctrl.delay_rts_before_send;
                rs485data.flags = 0;
+               if (rs485data.delay_rts_before_send != 0)
+                       rs485data.flags |= SER_RS485_RTS_BEFORE_SEND;
+               else
+                       rs485data.flags &= ~(SER_RS485_RTS_BEFORE_SEND);
+
                if (rs485ctrl.enabled)
                        rs485data.flags |= SER_RS485_ENABLED;
                else
@@ -3731,7 +3737,7 @@ rs_ioctl(struct tty_struct *tty, struct file * file,
                /* This is the ioctl to get RS485 data from user-space */
                if (copy_to_user((struct serial_rs485 *) arg,
                                        rs485data,
-                                       sizeof(serial_rs485)))
+                                       sizeof(struct serial_rs485)))
                        return -EFAULT;
                break;
        }
@@ -4527,6 +4533,7 @@ static int __init rs_init(void)
                /* Set sane defaults */
                info->rs485.flags &= ~(SER_RS485_RTS_ON_SEND);
                info->rs485.flags |= SER_RS485_RTS_AFTER_SEND;
+               info->rs485.flags &= ~(SER_RS485_RTS_BEFORE_SEND);
                info->rs485.delay_rts_before_send = 0;
                info->rs485.flags &= ~(SER_RS485_ENABLED);
 #endif
index fd0d1b98901c2a0c13cc925e078139be079d1f43..09615b51d5910e6b1b899e265836cb3137440ad1 100644 (file)
@@ -90,8 +90,8 @@ struct clk_rate_round_data {
 static long clk_rate_round_helper(struct clk_rate_round_data *rounder)
 {
        unsigned long rate_error, rate_error_prev = ~0UL;
-       unsigned long rate_best_fit = rounder->rate;
        unsigned long highest, lowest, freq;
+       long rate_best_fit = -ENOENT;
        int i;
 
        highest = 0;
@@ -146,7 +146,7 @@ long clk_rate_table_round(struct clk *clk,
        };
 
        if (clk->nr_freqs < 1)
-               return 0;
+               return -ENOSYS;
 
        return clk_rate_round_helper(&table_round);
 }
@@ -541,6 +541,98 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
 }
 EXPORT_SYMBOL_GPL(clk_round_rate);
 
+long clk_round_parent(struct clk *clk, unsigned long target,
+                     unsigned long *best_freq, unsigned long *parent_freq,
+                     unsigned int div_min, unsigned int div_max)
+{
+       struct cpufreq_frequency_table *freq, *best = NULL;
+       unsigned long error = ULONG_MAX, freq_high, freq_low, div;
+       struct clk *parent = clk_get_parent(clk);
+
+       if (!parent) {
+               *parent_freq = 0;
+               *best_freq = clk_round_rate(clk, target);
+               return abs(target - *best_freq);
+       }
+
+       for (freq = parent->freq_table; freq->frequency != CPUFREQ_TABLE_END;
+            freq++) {
+               if (freq->frequency == CPUFREQ_ENTRY_INVALID)
+                       continue;
+
+               if (unlikely(freq->frequency / target <= div_min - 1)) {
+                       unsigned long freq_max;
+
+                       freq_max = (freq->frequency + div_min / 2) / div_min;
+                       if (error > target - freq_max) {
+                               error = target - freq_max;
+                               best = freq;
+                               if (best_freq)
+                                       *best_freq = freq_max;
+                       }
+
+                       pr_debug("too low freq %lu, error %lu\n", freq->frequency,
+                                target - freq_max);
+
+                       if (!error)
+                               break;
+
+                       continue;
+               }
+
+               if (unlikely(freq->frequency / target >= div_max)) {
+                       unsigned long freq_min;
+
+                       freq_min = (freq->frequency + div_max / 2) / div_max;
+                       if (error > freq_min - target) {
+                               error = freq_min - target;
+                               best = freq;
+                               if (best_freq)
+                                       *best_freq = freq_min;
+                       }
+
+                       pr_debug("too high freq %lu, error %lu\n", freq->frequency,
+                                freq_min - target);
+
+                       if (!error)
+                               break;
+
+                       continue;
+               }
+
+               div = freq->frequency / target;
+               freq_high = freq->frequency / div;
+               freq_low = freq->frequency / (div + 1);
+
+               if (freq_high - target < error) {
+                       error = freq_high - target;
+                       best = freq;
+                       if (best_freq)
+                               *best_freq = freq_high;
+               }
+
+               if (target - freq_low < error) {
+                       error = target - freq_low;
+                       best = freq;
+                       if (best_freq)
+                               *best_freq = freq_low;
+               }
+
+               pr_debug("%u / %lu = %lu, / %lu = %lu, best %lu, parent %u\n",
+                        freq->frequency, div, freq_high, div + 1, freq_low,
+                        *best_freq, best->frequency);
+
+               if (!error)
+                       break;
+       }
+
+       if (parent_freq)
+               *parent_freq = best->frequency;
+
+       return error;
+}
+EXPORT_SYMBOL_GPL(clk_round_parent);
+
 #ifdef CONFIG_PM
 static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)
 {
index 873a99ff8f64a454a505d1838be751dad20ae181..e5e9e6735f7d62e3d585505de7be4fe379fbbd40 100644 (file)
@@ -79,7 +79,7 @@ static void __init intc_register_irq(struct intc_desc *desc,
         * Register the IRQ position with the global IRQ map, then insert
         * it in to the radix tree.
         */
-       irq_reserve_irqs(irq, 1);
+       irq_reserve_irq(irq);
 
        raw_spin_lock_irqsave(&intc_big_lock, flags);
        radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq));
index 4187cce20ffdc9cd0997b276e2f5e8dc020e2519..a3677c9dfe36e3fa6ebcac37bee81af58d9ece5c 100644 (file)
@@ -60,5 +60,5 @@ void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs)
        int i;
 
        for (i = 0; i < nr_vecs; i++)
-               irq_reserve_irqs(evt2irq(vectors[i].vect), 1);
+               irq_reserve_irq(evt2irq(vectors[i].vect));
 }
index b5a78a1f4421a0c19aa8735bd49f076fd8f91b46..709c836607de23636e6c567a38833cceff752b08 100644 (file)
 #include <linux/spi/spi.h>
 #include <linux/of_spi.h>
 
-
-/* SPI bustype and spi_master class are registered after board init code
- * provides the SPI device tables, ensuring that both are present by the
- * time controller driver registration causes spi_devices to "enumerate".
- */
 static void spidev_release(struct device *dev)
 {
        struct spi_device       *spi = to_spi_device(dev);
@@ -202,11 +197,16 @@ EXPORT_SYMBOL_GPL(spi_register_driver);
 
 struct boardinfo {
        struct list_head        list;
-       unsigned                n_board_info;
-       struct spi_board_info   board_info[0];
+       struct spi_board_info   board_info;
 };
 
 static LIST_HEAD(board_list);
+static LIST_HEAD(spi_master_list);
+
+/*
+ * Used to protect add/del opertion for board_info list and
+ * spi_master list, and their matching process
+ */
 static DEFINE_MUTEX(board_lock);
 
 /**
@@ -300,16 +300,16 @@ int spi_add_device(struct spi_device *spi)
         */
        status = spi_setup(spi);
        if (status < 0) {
-               dev_err(dev, "can't %s %s, status %d\n",
-                               "setup", dev_name(&spi->dev), status);
+               dev_err(dev, "can't setup %s, status %d\n",
+                               dev_name(&spi->dev), status);
                goto done;
        }
 
        /* Device may be bound to an active driver when this returns */
        status = device_add(&spi->dev);
        if (status < 0)
-               dev_err(dev, "can't %s %s, status %d\n",
-                               "add", dev_name(&spi->dev), status);
+               dev_err(dev, "can't add %s, status %d\n",
+                               dev_name(&spi->dev), status);
        else
                dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));
 
@@ -371,6 +371,20 @@ struct spi_device *spi_new_device(struct spi_master *master,
 }
 EXPORT_SYMBOL_GPL(spi_new_device);
 
+static void spi_match_master_to_boardinfo(struct spi_master *master,
+                               struct spi_board_info *bi)
+{
+       struct spi_device *dev;
+
+       if (master->bus_num != bi->bus_num)
+               return;
+
+       dev = spi_new_device(master, bi);
+       if (!dev)
+               dev_err(master->dev.parent, "can't create new device for %s\n",
+                       bi->modalias);
+}
+
 /**
  * spi_register_board_info - register SPI devices for a given board
  * @info: array of chip descriptors
@@ -393,43 +407,25 @@ EXPORT_SYMBOL_GPL(spi_new_device);
 int __init
 spi_register_board_info(struct spi_board_info const *info, unsigned n)
 {
-       struct boardinfo        *bi;
+       struct boardinfo *bi;
+       int i;
 
-       bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);
+       bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
        if (!bi)
                return -ENOMEM;
-       bi->n_board_info = n;
-       memcpy(bi->board_info, info, n * sizeof *info);
 
-       mutex_lock(&board_lock);
-       list_add_tail(&bi->list, &board_list);
-       mutex_unlock(&board_lock);
-       return 0;
-}
+       for (i = 0; i < n; i++, bi++, info++) {
+               struct spi_master *master;
 
-/* FIXME someone should add support for a __setup("spi", ...) that
- * creates board info from kernel command lines
- */
-
-static void scan_boardinfo(struct spi_master *master)
-{
-       struct boardinfo        *bi;
-
-       mutex_lock(&board_lock);
-       list_for_each_entry(bi, &board_list, list) {
-               struct spi_board_info   *chip = bi->board_info;
-               unsigned                n;
-
-               for (n = bi->n_board_info; n > 0; n--, chip++) {
-                       if (chip->bus_num != master->bus_num)
-                               continue;
-                       /* NOTE: this relies on spi_new_device to
-                        * issue diagnostics when given bogus inputs
-                        */
-                       (void) spi_new_device(master, chip);
-               }
+               memcpy(&bi->board_info, info, sizeof(*info));
+               mutex_lock(&board_lock);
+               list_add_tail(&bi->list, &board_list);
+               list_for_each_entry(master, &spi_master_list, list)
+                       spi_match_master_to_boardinfo(master, &bi->board_info);
+               mutex_unlock(&board_lock);
        }
-       mutex_unlock(&board_lock);
+
+       return 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -512,6 +508,7 @@ int spi_register_master(struct spi_master *master)
 {
        static atomic_t         dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
        struct device           *dev = master->dev.parent;
+       struct boardinfo        *bi;
        int                     status = -ENODEV;
        int                     dynamic = 0;
 
@@ -547,8 +544,12 @@ int spi_register_master(struct spi_master *master)
        dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
                        dynamic ? " (dynamic)" : "");
 
-       /* populate children from any spi device tables */
-       scan_boardinfo(master);
+       mutex_lock(&board_lock);
+       list_add_tail(&master->list, &spi_master_list);
+       list_for_each_entry(bi, &board_list, list)
+               spi_match_master_to_boardinfo(master, &bi->board_info);
+       mutex_unlock(&board_lock);
+
        status = 0;
 
        /* Register devices from the device tree */
@@ -579,7 +580,12 @@ void spi_unregister_master(struct spi_master *master)
 {
        int dummy;
 
-       dummy = device_for_each_child(&master->dev, NULL, __unregister);
+       mutex_lock(&board_lock);
+       list_del(&master->list);
+       mutex_unlock(&board_lock);
+
+       dummy = device_for_each_child(master->dev.parent, &master->dev,
+                                       __unregister);
        device_unregister(&master->dev);
 }
 EXPORT_SYMBOL_GPL(spi_unregister_master);
@@ -652,7 +658,7 @@ int spi_setup(struct spi_device *spi)
         */
        bad_bits = spi->mode & ~spi->master->mode_bits;
        if (bad_bits) {
-               dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+               dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
                        bad_bits);
                return -EINVAL;
        }
index ab483a0ec6d05b7738ab85aed075ee0a293598bf..3f223511127b56c9a6800743991aea342e5e2e92 100644 (file)
@@ -504,6 +504,15 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id)
                "in dma_irq_handler dmastat:0x%x spistat:0x%x\n",
                dmastat, spistat);
 
+       if (drv_data->rx != NULL) {
+               u16 cr = read_CTRL(drv_data);
+               /* discard old RX data and clear RXS */
+               bfin_spi_dummy_read(drv_data);
+               write_CTRL(drv_data, cr & ~BIT_CTL_ENABLE); /* Disable SPI */
+               write_CTRL(drv_data, cr & ~BIT_CTL_TIMOD); /* Restore State */
+               write_STAT(drv_data, BIT_STAT_CLR); /* Clear Status */
+       }
+
        clear_dma_irqstat(drv_data->dma_channel);
 
        /*
@@ -1099,12 +1108,15 @@ static int bfin_spi_setup(struct spi_device *spi)
        }
 
        if (chip->chip_select_num >= MAX_CTRL_CS) {
-               ret = gpio_request(chip->cs_gpio, spi->modalias);
-               if (ret) {
-                       dev_err(&spi->dev, "gpio_request() error\n");
-                       goto pin_error;
+               /* Only request on first setup */
+               if (spi_get_ctldata(spi) == NULL) {
+                       ret = gpio_request(chip->cs_gpio, spi->modalias);
+                       if (ret) {
+                               dev_err(&spi->dev, "gpio_request() error\n");
+                               goto pin_error;
+                       }
+                       gpio_direction_output(chip->cs_gpio, 1);
                }
-               gpio_direction_output(chip->cs_gpio, 1);
        }
 
        dev_dbg(&spi->dev, "setup spi chip %s, width is %d, dma is %d\n",
index 22c6c6659f5b5f9a004ed25ae4543e01c200380b..ee8b47746a155ece0fbc559803a40ecb71e6f21b 100644 (file)
@@ -285,9 +285,9 @@ A_STATUS SetupHIFScatterSupport(HIF_DEVICE *device, HIF_DEVICE_SCATTER_SUPPORT_I
     do {
         
             /* check if host supports scatter requests and it meets our requirements */
-        if (device->func->card->host->max_hw_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
+        if (device->func->card->host->max_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HIF-SCATTER : host only supports scatter of : %d entries, need: %d \n",
-                    device->func->card->host->max_hw_segs, MAX_SCATTER_ENTRIES_PER_REQ));
+                    device->func->card->host->max_segs, MAX_SCATTER_ENTRIES_PER_REQ));
             status = A_ENOTSUP;
             break;    
         }
index c196098f0859c2aa1c60df2d2c9dcc1bd5957110..6b8eeea475cf4e9e5a59f9b0d821121229d4cea5 100644 (file)
@@ -198,8 +198,8 @@ int ar6000_htc_raw_open(AR_SOFTC_T *ar)
         
     for (streamID = HTC_RAW_STREAM_0; streamID < HTC_RAW_STREAM_NUM_MAX; streamID++) {
         /* Initialize the data structures */
-        init_MUTEX(&arRaw->raw_htc_read_sem[streamID]);
-        init_MUTEX(&arRaw->raw_htc_write_sem[streamID]);
+       sema_init(&arRaw->raw_htc_read_sem[streamID], 1);
+       sema_init(&arRaw->raw_htc_write_sem[streamID], 1);
         init_waitqueue_head(&arRaw->raw_htc_read_queue[streamID]);
         init_waitqueue_head(&arRaw->raw_htc_write_queue[streamID]);
 
diff --git a/drivers/staging/ath6kl/os/linux/include/athendpack_linux.h b/drivers/staging/ath6kl/os/linux/include/athendpack_linux.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h b/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h
deleted file mode 100644 (file)
index e69de29..0000000
index e5357875661f5227a4cdd81dbd3f6b2e53e20fb4..bbbe7c5f7492573508d5027b03cd1df9a187b561 100644 (file)
@@ -1929,7 +1929,7 @@ dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
                goto fail;
 
        net->netdev_ops = NULL;
-       init_MUTEX(&dhd->proto_sem);
+       sema_init(&dhd->proto_sem, 1);
        /* Initialize other structure content */
        init_waitqueue_head(&dhd->ioctl_resp_wait);
        init_waitqueue_head(&dhd->ctrl_wait);
@@ -1977,7 +1977,7 @@ dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
        dhd->timer.function = dhd_watchdog;
 
        /* Initialize thread based operation and lock */
-       init_MUTEX(&dhd->sdsem);
+       sema_init(&dhd->sdsem, 1);
        if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0))
                dhd->threads_only = true;
        else
index ad635ee7758e2aca45e3d6cb5d60d67c19c48618..d060377629ac2fc69320a17600a1371b201dec40 100644 (file)
@@ -866,7 +866,7 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs,
        spin_lock_init(&wl->rpcq_lock);
        spin_lock_init(&wl->txq_lock);
 
-       init_MUTEX(&wl->sem);
+       sema_init(&wl->sem, 1);
 #else
        spin_lock_init(&wl->lock);
        spin_lock_init(&wl->isr_lock);
index 0560a74515125c6668e225ab433987b91dd4e365..06059850dae2e3d2b7a4d06e16a9337c2cfefab4 100644 (file)
@@ -262,7 +262,7 @@ struct dt9812_usb_cmd {
 
 #define DT9812_NUM_SLOTS       16
 
-static DECLARE_MUTEX(dt9812_mutex);
+static DEFINE_SEMAPHORE(dt9812_mutex);
 
 static const struct usb_device_id dt9812_table[] = {
        {USB_DEVICE(0x0867, 0x9812)},
index 6131e2dd0591ba60b38c6b7cc755e326e5382123..1f177a67ff114f9098f3bcdb282068978c6567e3 100644 (file)
@@ -315,7 +315,7 @@ struct usbduxsub {
  */
 static struct usbduxsub usbduxsub[NUMUSBDUX];
 
-static DECLARE_MUTEX(start_stop_sem);
+static DEFINE_SEMAPHORE(start_stop_sem);
 
 /*
  * Stops the data acquision
@@ -2367,7 +2367,7 @@ static int usbduxsub_probe(struct usb_interface *uinterf,
        dev_dbg(dev, "comedi_: usbdux: "
                "usbduxsub[%d] is ready to connect to comedi.\n", index);
 
-       init_MUTEX(&(usbduxsub[index].sem));
+       sema_init(&(usbduxsub[index].sem), 1);
        /* save a pointer to the usb device */
        usbduxsub[index].usbdev = udev;
 
index 0a164a9a66c3b0024890b61a76e0178abf576023..5b15e6df54e653cb4f7e815979c0c7f645722a23 100644 (file)
@@ -199,7 +199,7 @@ struct usbduxfastsub_s {
  */
 static struct usbduxfastsub_s usbduxfastsub[NUMUSBDUXFAST];
 
-static DECLARE_MUTEX(start_stop_sem);
+static DEFINE_SEMAPHORE(start_stop_sem);
 
 /*
  * bulk transfers to usbduxfast
@@ -1504,7 +1504,7 @@ static int usbduxfastsub_probe(struct usb_interface *uinterf,
               "connect to comedi.\n", index);
 #endif
 
-       init_MUTEX(&(usbduxfastsub[index].sem));
+       sema_init(&(usbduxfastsub[index].sem), 1);
        /* save a pointer to the usb device */
        usbduxfastsub[index].usbdev = udev;
 
index ea268edbf43b0916be95f4e0d5f20b38665a05fb..23fa049b51f22d941ebd8415f375c93ad3462898 100644 (file)
@@ -1158,7 +1158,7 @@ static int msm_fb_release(struct fb_info *info, int user)
        return ret;
 }
 
-DECLARE_MUTEX(msm_fb_pan_sem);
+DEFINE_SEMAPHORE(msm_fb_pan_sem);
 
 static int msm_fb_pan_display(struct fb_var_screeninfo *var,
                              struct fb_info *info)
@@ -1962,7 +1962,7 @@ static int msmfb_overlay_play(struct fb_info *info, unsigned long *argp)
 
 #endif
 
-DECLARE_MUTEX(msm_fb_ioctl_ppp_sem);
+DEFINE_SEMAPHORE(msm_fb_ioctl_ppp_sem);
 DEFINE_MUTEX(msm_fb_ioctl_lut_sem);
 DEFINE_MUTEX(msm_fb_ioctl_hist_sem);
 
index 7fca42c7c0d40f9b0d103f8a3f93f789828d0b68..d1674cd282dcd7deb370cca6b75c8f0f69b3ed73 100644 (file)
@@ -161,7 +161,7 @@ static inline u32 _down_sema(struct semaphore *sema)
 
 static inline void _rtl_rwlock_init(struct semaphore *prwlock)
 {
-       init_MUTEX(prwlock);
+       sema_init(prwlock, 1);
 }
 
 static inline void _init_listhead(struct list_head *list)
index f9c493591ce75f151ead6fbbeed379cb5a8a1290..540a984bb5160d5942902575803c6c79b087d507 100644 (file)
@@ -537,7 +537,7 @@ static int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
        server->mnt = NULL;
        server->sock_file = NULL;
        init_waitqueue_head(&server->conn_wq);
-       init_MUTEX(&server->sem);
+       sema_init(&server->sem, 1);
        INIT_LIST_HEAD(&server->entry);
        INIT_LIST_HEAD(&server->xmitq);
        INIT_LIST_HEAD(&server->recvq);
index bbf3d9c4abb03aa6dc4b17f9e3f0d123cc7306d7..097e82bc7a6315d92bd0c158bca8a10340f6c22c 100644 (file)
@@ -766,7 +766,7 @@ static int solo_enc_open(struct file *file)
                                    &solo_enc->lock,
                                    V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                    V4L2_FIELD_INTERLACED,
-                                   sizeof(struct videobuf_buffer), fh);
+                                   sizeof(struct videobuf_buffer), fh, NULL);
 
        spin_unlock(&solo_enc->lock);
 
index 9731fa02b5e80702c380e42dfd57c996dad03a3e..6ffd21de837d8bf5161d6654206ce918439cc78f 100644 (file)
@@ -437,7 +437,7 @@ static int solo_v4l2_open(struct file *file)
                                    &solo_dev->pdev->dev, &fh->slock,
                                    V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                    SOLO_DISP_PIX_FIELD,
-                                   sizeof(struct videobuf_buffer), fh);
+                                   sizeof(struct videobuf_buffer), fh, NULL);
 
        return 0;
 }
index 3e46866dd2791dc3b66724bd64e96836a1159dfd..93f625fc852b20d991012ffa6d61b05b693690a6 100644 (file)
@@ -320,7 +320,6 @@ static struct i2c_algorithm tm6000_algo = {
 
 static struct i2c_adapter tm6000_adap_template = {
        .owner = THIS_MODULE,
-       .class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
        .name = "tm6000",
        .algo = &tm6000_algo,
 };
index f428a7af357a6812fe1f0c7ca8f73a7f88aecf24..e1851f00be568f07e17fbd6c45070bdc9d01de93 100644 (file)
@@ -157,7 +157,7 @@ struct cyasblkdev_blk_data {
 /* pointer to west bridge block data device superstructure */
 static struct cyasblkdev_blk_data *gl_bd;
 
-static DECLARE_MUTEX(open_lock);
+static DEFINE_SEMAPHORE(open_lock);
 
 /* local forwardd declarationss  */
 static cy_as_device_handle *cyas_dev_handle;
index 24e959eca4127a0db1078a60466723d569304be5..0bbb8a3e191df18963e98bafeaef480da125a3a2 100644 (file)
@@ -334,7 +334,7 @@ int cyasblkdev_init_queue(struct cyasblkdev_queue *bq, spinlock_t *lock)
 
        init_completion(&bq->thread_complete);
        init_waitqueue_head(&bq->thread_wq);
-       init_MUTEX(&bq->thread_sem);
+       sema_init(&bq->thread_sem, 1);
 
        ret = kernel_thread(cyasblkdev_queue_thread, bq, CLONE_KERNEL);
        if (ret >= 0) {
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
new file mode 100644 (file)
index 0000000..c43ef48
--- /dev/null
@@ -0,0 +1,11 @@
+obj-y                          += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
+                                  tty_buffer.o tty_port.o tty_mutex.o
+obj-$(CONFIG_LEGACY_PTYS)      += pty.o
+obj-$(CONFIG_UNIX98_PTYS)      += pty.o
+obj-$(CONFIG_AUDIT)            += tty_audit.o
+obj-$(CONFIG_MAGIC_SYSRQ)      += sysrq.o
+obj-$(CONFIG_N_HDLC)           += n_hdlc.o
+obj-$(CONFIG_N_GSM)            += n_gsm.o
+obj-$(CONFIG_R3964)            += n_r3964.o
+
+obj-y                          += vt/
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
new file mode 100644 (file)
index 0000000..04ef3ef
--- /dev/null
@@ -0,0 +1,2763 @@
+/*
+ * n_gsm.c GSM 0710 tty multiplexor
+ * Copyright (c) 2009/10 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *     * THIS IS A DEVELOPMENT SNAPSHOT IT IS NOT A FINAL RELEASE *
+ *
+ * TO DO:
+ *     Mostly done:    ioctls for setting modes/timing
+ *     Partly done:    hooks so you can pull off frames to non tty devs
+ *     Restart DLCI 0 when it closes ?
+ *     Test basic encoding
+ *     Improve the tx engine
+ *     Resolve tx side locking by adding a queue_head and routing
+ *             all control traffic via it
+ *     General tidy/document
+ *     Review the locking/move to refcounts more (mux now moved to an
+ *             alloc/free model ready)
+ *     Use newest tty open/close port helpers and install hooks
+ *     What to do about power functions ?
+ *     Termios setting and negotiation
+ *     Do we need a 'which mux are you' ioctl to correlate mux and tty sets
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/bitops.h>
+#include <linux/file.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/tty_flip.h>
+#include <linux/tty_driver.h>
+#include <linux/serial.h>
+#include <linux/kfifo.h>
+#include <linux/skbuff.h>
+#include <linux/gsmmux.h>
+
+static int debug;
+module_param(debug, int, 0600);
+
+#define T1     (HZ/10)
+#define T2     (HZ/3)
+#define N2     3
+
+/* Use long timers for testing at low speed with debug on */
+#ifdef DEBUG_TIMING
+#define T1     HZ
+#define T2     (2 * HZ)
+#endif
+
+/* Semi-arbitary buffer size limits. 0710 is normally run with 32-64 byte
+   limits so this is plenty */
+#define MAX_MRU 512
+#define MAX_MTU 512
+
+/*
+ *     Each block of data we have queued to go out is in the form of
+ *     a gsm_msg which holds everything we need in a link layer independant
+ *     format
+ */
+
+struct gsm_msg {
+       struct gsm_msg *next;
+       u8 addr;                /* DLCI address + flags */
+       u8 ctrl;                /* Control byte + flags */
+       unsigned int len;       /* Length of data block (can be zero) */
+       unsigned char *data;    /* Points into buffer but not at the start */
+       unsigned char buffer[0];
+};
+
+/*
+ *     Each active data link has a gsm_dlci structure associated which ties
+ *     the link layer to an optional tty (if the tty side is open). To avoid
+ *     complexity right now these are only ever freed up when the mux is
+ *     shut down.
+ *
+ *     At the moment we don't free DLCI objects until the mux is torn down
+ *     this avoid object life time issues but might be worth review later.
+ */
+
+struct gsm_dlci {
+       struct gsm_mux *gsm;
+       int addr;
+       int state;
+#define DLCI_CLOSED            0
+#define DLCI_OPENING           1       /* Sending SABM not seen UA */
+#define DLCI_OPEN              2       /* SABM/UA complete */
+#define DLCI_CLOSING           3       /* Sending DISC not seen UA/DM */
+
+       /* Link layer */
+       spinlock_t lock;        /* Protects the internal state */
+       struct timer_list t1;   /* Retransmit timer for SABM and UA */
+       int retries;
+       /* Uplink tty if active */
+       struct tty_port port;   /* The tty bound to this DLCI if there is one */
+       struct kfifo *fifo;     /* Queue fifo for the DLCI */
+       struct kfifo _fifo;     /* For new fifo API porting only */
+       int adaption;           /* Adaption layer in use */
+       u32 modem_rx;           /* Our incoming virtual modem lines */
+       u32 modem_tx;           /* Our outgoing modem lines */
+       int dead;               /* Refuse re-open */
+       /* Flow control */
+       int throttled;          /* Private copy of throttle state */
+       int constipated;        /* Throttle status for outgoing */
+       /* Packetised I/O */
+       struct sk_buff *skb;    /* Frame being sent */
+       struct sk_buff_head skb_list;   /* Queued frames */
+       /* Data handling callback */
+       void (*data)(struct gsm_dlci *dlci, u8 *data, int len);
+};
+
+/* DLCI 0, 62/63 are special or reseved see gsmtty_open */
+
+#define NUM_DLCI               64
+
+/*
+ *     DLCI 0 is used to pass control blocks out of band of the data
+ *     flow (and with a higher link priority). One command can be outstanding
+ *     at a time and we use this structure to manage them. They are created
+ *     and destroyed by the user context, and updated by the receive paths
+ *     and timers
+ */
+
+struct gsm_control {
+       u8 cmd;         /* Command we are issuing */
+       u8 *data;       /* Data for the command in case we retransmit */
+       int len;        /* Length of block for retransmission */
+       int done;       /* Done flag */
+       int error;      /* Error if any */
+};
+
+/*
+ *     Each GSM mux we have is represented by this structure. If we are
+ *     operating as an ldisc then we use this structure as our ldisc
+ *     state. We need to sort out lifetimes and locking with respect
+ *     to the gsm mux array. For now we don't free DLCI objects that
+ *     have been instantiated until the mux itself is terminated.
+ *
+ *     To consider further: tty open versus mux shutdown.
+ */
+
+struct gsm_mux {
+       struct tty_struct *tty;         /* The tty our ldisc is bound to */
+       spinlock_t lock;
+
+       /* Events on the GSM channel */
+       wait_queue_head_t event;
+
+       /* Bits for GSM mode decoding */
+
+       /* Framing Layer */
+       unsigned char *buf;
+       int state;
+#define GSM_SEARCH             0
+#define GSM_START              1
+#define GSM_ADDRESS            2
+#define GSM_CONTROL            3
+#define GSM_LEN                        4
+#define GSM_DATA               5
+#define GSM_FCS                        6
+#define GSM_OVERRUN            7
+       unsigned int len;
+       unsigned int address;
+       unsigned int count;
+       int escape;
+       int encoding;
+       u8 control;
+       u8 fcs;
+       u8 *txframe;                    /* TX framing buffer */
+
+       /* Methods for the receiver side */
+       void (*receive)(struct gsm_mux *gsm, u8 ch);
+       void (*error)(struct gsm_mux *gsm, u8 ch, u8 flag);
+       /* And transmit side */
+       int (*output)(struct gsm_mux *mux, u8 *data, int len);
+
+       /* Link Layer */
+       unsigned int mru;
+       unsigned int mtu;
+       int initiator;                  /* Did we initiate connection */
+       int dead;                       /* Has the mux been shut down */
+       struct gsm_dlci *dlci[NUM_DLCI];
+       int constipated;                /* Asked by remote to shut up */
+
+       spinlock_t tx_lock;
+       unsigned int tx_bytes;          /* TX data outstanding */
+#define TX_THRESH_HI           8192
+#define TX_THRESH_LO           2048
+       struct gsm_msg *tx_head;        /* Pending data packets */
+       struct gsm_msg *tx_tail;
+
+       /* Control messages */
+       struct timer_list t2_timer;     /* Retransmit timer for commands */
+       int cretries;                   /* Command retry counter */
+       struct gsm_control *pending_cmd;/* Our current pending command */
+       spinlock_t control_lock;        /* Protects the pending command */
+
+       /* Configuration */
+       int adaption;           /* 1 or 2 supported */
+       u8 ftype;               /* UI or UIH */
+       int t1, t2;             /* Timers in 1/100th of a sec */
+       int n2;                 /* Retry count */
+
+       /* Statistics (not currently exposed) */
+       unsigned long bad_fcs;
+       unsigned long malformed;
+       unsigned long io_error;
+       unsigned long bad_size;
+       unsigned long unsupported;
+};
+
+
+/*
+ *     Mux objects - needed so that we can translate a tty index into the
+ *     relevant mux and DLCI.
+ */
+
+#define MAX_MUX                4                       /* 256 minors */
+static struct gsm_mux *gsm_mux[MAX_MUX];       /* GSM muxes */
+static spinlock_t gsm_mux_lock;
+
+/*
+ *     This section of the driver logic implements the GSM encodings
+ *     both the basic and the 'advanced'. Reliable transport is not
+ *     supported.
+ */
+
+#define CR                     0x02
+#define EA                     0x01
+#define        PF                      0x10
+
+/* I is special: the rest are ..*/
+#define RR                     0x01
+#define UI                     0x03
+#define RNR                    0x05
+#define REJ                    0x09
+#define DM                     0x0F
+#define SABM                   0x2F
+#define DISC                   0x43
+#define UA                     0x63
+#define        UIH                     0xEF
+
+/* Channel commands */
+#define CMD_NSC                        0x09
+#define CMD_TEST               0x11
+#define CMD_PSC                        0x21
+#define CMD_RLS                        0x29
+#define CMD_FCOFF              0x31
+#define CMD_PN                 0x41
+#define CMD_RPN                        0x49
+#define CMD_FCON               0x51
+#define CMD_CLD                        0x61
+#define CMD_SNC                        0x69
+#define CMD_MSC                        0x71
+
+/* Virtual modem bits */
+#define MDM_FC                 0x01
+#define MDM_RTC                        0x02
+#define MDM_RTR                        0x04
+#define MDM_IC                 0x20
+#define MDM_DV                 0x40
+
+#define GSM0_SOF               0xF9
+#define GSM1_SOF               0x7E
+#define GSM1_ESCAPE            0x7D
+#define GSM1_ESCAPE_BITS       0x20
+#define XON                    0x11
+#define XOFF                   0x13
+
+static const struct tty_port_operations gsm_port_ops;
+
+/*
+ *     CRC table for GSM 0710
+ */
+
+static const u8 gsm_fcs8[256] = {
+       0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75,
+       0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
+       0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69,
+       0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
+       0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D,
+       0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
+       0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51,
+       0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
+       0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05,
+       0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
+       0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19,
+       0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
+       0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D,
+       0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
+       0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21,
+       0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
+       0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95,
+       0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
+       0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89,
+       0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
+       0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD,
+       0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
+       0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1,
+       0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
+       0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5,
+       0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
+       0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9,
+       0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
+       0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD,
+       0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
+       0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1,
+       0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
+};
+
+#define INIT_FCS       0xFF
+#define GOOD_FCS       0xCF
+
+/**
+ *     gsm_fcs_add     -       update FCS
+ *     @fcs: Current FCS
+ *     @c: Next data
+ *
+ *     Update the FCS to include c. Uses the algorithm in the specification
+ *     notes.
+ */
+
+static inline u8 gsm_fcs_add(u8 fcs, u8 c)
+{
+       return gsm_fcs8[fcs ^ c];
+}
+
+/**
+ *     gsm_fcs_add_block       -       update FCS for a block
+ *     @fcs: Current FCS
+ *     @c: buffer of data
+ *     @len: length of buffer
+ *
+ *     Update the FCS to include c. Uses the algorithm in the specification
+ *     notes.
+ */
+
+static inline u8 gsm_fcs_add_block(u8 fcs, u8 *c, int len)
+{
+       while (len--)
+               fcs = gsm_fcs8[fcs ^ *c++];
+       return fcs;
+}
+
+/**
+ *     gsm_read_ea             -       read a byte into an EA
+ *     @val: variable holding value
+ *     c: byte going into the EA
+ *
+ *     Processes one byte of an EA. Updates the passed variable
+ *     and returns 1 if the EA is now completely read
+ */
+
+static int gsm_read_ea(unsigned int *val, u8 c)
+{
+       /* Add the next 7 bits into the value */
+       *val <<= 7;
+       *val |= c >> 1;
+       /* Was this the last byte of the EA 1 = yes*/
+       return c & EA;
+}
+
+/**
+ *     gsm_encode_modem        -       encode modem data bits
+ *     @dlci: DLCI to encode from
+ *
+ *     Returns the correct GSM encoded modem status bits (6 bit field) for
+ *     the current status of the DLCI and attached tty object
+ */
+
+static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
+{
+       u8 modembits = 0;
+       /* FC is true flow control not modem bits */
+       if (dlci->throttled)
+               modembits |= MDM_FC;
+       if (dlci->modem_tx & TIOCM_DTR)
+               modembits |= MDM_RTC;
+       if (dlci->modem_tx & TIOCM_RTS)
+               modembits |= MDM_RTR;
+       if (dlci->modem_tx & TIOCM_RI)
+               modembits |= MDM_IC;
+       if (dlci->modem_tx & TIOCM_CD)
+               modembits |= MDM_DV;
+       return modembits;
+}
+
+/**
+ *     gsm_print_packet        -       display a frame for debug
+ *     @hdr: header to print before decode
+ *     @addr: address EA from the frame
+ *     @cr: C/R bit from the frame
+ *     @control: control including PF bit
+ *     @data: following data bytes
+ *     @dlen: length of data
+ *
+ *     Displays a packet in human readable format for debugging purposes. The
+ *     style is based on amateur radio LAP-B dump display.
+ */
+
+static void gsm_print_packet(const char *hdr, int addr, int cr,
+                                       u8 control, const u8 *data, int dlen)
+{
+       if (!(debug & 1))
+               return;
+
+       printk(KERN_INFO "%s %d) %c: ", hdr, addr, "RC"[cr]);
+
+       switch (control & ~PF) {
+       case SABM:
+               printk(KERN_CONT "SABM");
+               break;
+       case UA:
+               printk(KERN_CONT "UA");
+               break;
+       case DISC:
+               printk(KERN_CONT "DISC");
+               break;
+       case DM:
+               printk(KERN_CONT "DM");
+               break;
+       case UI:
+               printk(KERN_CONT "UI");
+               break;
+       case UIH:
+               printk(KERN_CONT "UIH");
+               break;
+       default:
+               if (!(control & 0x01)) {
+                       printk(KERN_CONT "I N(S)%d N(R)%d",
+                               (control & 0x0E) >> 1, (control & 0xE)>> 5);
+               } else switch (control & 0x0F) {
+               case RR:
+                       printk("RR(%d)", (control & 0xE0) >> 5);
+                       break;
+               case RNR:
+                       printk("RNR(%d)", (control & 0xE0) >> 5);
+                       break;
+               case REJ:
+                       printk("REJ(%d)", (control & 0xE0) >> 5);
+                       break;
+               default:
+                       printk(KERN_CONT "[%02X]", control);
+               }
+       }
+
+       if (control & PF)
+               printk(KERN_CONT "(P)");
+       else
+               printk(KERN_CONT "(F)");
+
+       if (dlen) {
+               int ct = 0;
+               while (dlen--) {
+                       if (ct % 8 == 0)
+                               printk(KERN_CONT "\n    ");
+                       printk(KERN_CONT "%02X ", *data++);
+                       ct++;
+               }
+       }
+       printk(KERN_CONT "\n");
+}
+
+
+/*
+ *     Link level transmission side
+ */
+
+/**
+ *     gsm_stuff_packet        -       bytestuff a packet
+ *     @ibuf: input
+ *     @obuf: output
+ *     @len: length of input
+ *
+ *     Expand a buffer by bytestuffing it. The worst case size change
+ *     is doubling and the caller is responsible for handing out
+ *     suitable sized buffers.
+ */
+
+static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
+{
+       int olen = 0;
+       while (len--) {
+               if (*input == GSM1_SOF || *input == GSM1_ESCAPE
+                   || *input == XON || *input == XOFF) {
+                       *output++ = GSM1_ESCAPE;
+                       *output++ = *input++ ^ GSM1_ESCAPE_BITS;
+                       olen++;
+               } else
+                       *output++ = *input++;
+               olen++;
+       }
+       return olen;
+}
+
+static void hex_packet(const unsigned char *p, int len)
+{
+       int i;
+       for (i = 0; i < len; i++) {
+               if (i && (i % 16) == 0)
+                       printk("\n");
+               printk("%02X ", *p++);
+       }
+       printk("\n");
+}
+
+/**
+ *     gsm_send        -       send a control frame
+ *     @gsm: our GSM mux
+ *     @addr: address for control frame
+ *     @cr: command/response bit
+ *     @control:  control byte including PF bit
+ *
+ *     Format up and transmit a control frame. These do not go via the
+ *     queueing logic as they should be transmitted ahead of data when
+ *     they are needed.
+ *
+ *     FIXME: Lock versus data TX path
+ */
+
+static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
+{
+       int len;
+       u8 cbuf[10];
+       u8 ibuf[3];
+
+       switch (gsm->encoding) {
+       case 0:
+               cbuf[0] = GSM0_SOF;
+               cbuf[1] = (addr << 2) | (cr << 1) | EA;
+               cbuf[2] = control;
+               cbuf[3] = EA;   /* Length of data = 0 */
+               cbuf[4] = 0xFF - gsm_fcs_add_block(INIT_FCS, cbuf + 1, 3);
+               cbuf[5] = GSM0_SOF;
+               len = 6;
+               break;
+       case 1:
+       case 2:
+               /* Control frame + packing (but not frame stuffing) in mode 1 */
+               ibuf[0] = (addr << 2) | (cr << 1) | EA;
+               ibuf[1] = control;
+               ibuf[2] = 0xFF - gsm_fcs_add_block(INIT_FCS, ibuf, 2);
+               /* Stuffing may double the size worst case */
+               len = gsm_stuff_frame(ibuf, cbuf + 1, 3);
+               /* Now add the SOF markers */
+               cbuf[0] = GSM1_SOF;
+               cbuf[len + 1] = GSM1_SOF;
+               /* FIXME: we can omit the lead one in many cases */
+               len += 2;
+               break;
+       default:
+               WARN_ON(1);
+               return;
+       }
+       gsm->output(gsm, cbuf, len);
+       gsm_print_packet("-->", addr, cr, control, NULL, 0);
+}
+
+/**
+ *     gsm_response    -       send a control response
+ *     @gsm: our GSM mux
+ *     @addr: address for control frame
+ *     @control:  control byte including PF bit
+ *
+ *     Format up and transmit a link level response frame.
+ */
+
+static inline void gsm_response(struct gsm_mux *gsm, int addr, int control)
+{
+       gsm_send(gsm, addr, 0, control);
+}
+
+/**
+ *     gsm_command     -       send a control command
+ *     @gsm: our GSM mux
+ *     @addr: address for control frame
+ *     @control:  control byte including PF bit
+ *
+ *     Format up and transmit a link level command frame.
+ */
+
+static inline void gsm_command(struct gsm_mux *gsm, int addr, int control)
+{
+       gsm_send(gsm, addr, 1, control);
+}
+
+/* Data transmission */
+
+#define HDR_LEN                6       /* ADDR CTRL [LEN.2] DATA FCS */
+
+/**
+ *     gsm_data_alloc          -       allocate data frame
+ *     @gsm: GSM mux
+ *     @addr: DLCI address
+ *     @len: length excluding header and FCS
+ *     @ctrl: control byte
+ *
+ *     Allocate a new data buffer for sending frames with data. Space is left
+ *     at the front for header bytes but that is treated as an implementation
+ *     detail and not for the high level code to use
+ */
+
+static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
+                                                               u8 ctrl)
+{
+       struct gsm_msg *m = kmalloc(sizeof(struct gsm_msg) + len + HDR_LEN,
+                                                               GFP_ATOMIC);
+       if (m == NULL)
+               return NULL;
+       m->data = m->buffer + HDR_LEN - 1;      /* Allow for FCS */
+       m->len = len;
+       m->addr = addr;
+       m->ctrl = ctrl;
+       m->next = NULL;
+       return m;
+}
+
+/**
+ *     gsm_data_kick           -       poke the queue
+ *     @gsm: GSM Mux
+ *
+ *     The tty device has called us to indicate that room has appeared in
+ *     the transmit queue. Ram more data into the pipe if we have any
+ *
+ *     FIXME: lock against link layer control transmissions
+ */
+
+static void gsm_data_kick(struct gsm_mux *gsm)
+{
+       struct gsm_msg *msg = gsm->tx_head;
+       int len;
+       int skip_sof = 0;
+
+       /* FIXME: We need to apply this solely to data messages */
+       if (gsm->constipated)
+               return;
+
+       while (gsm->tx_head != NULL) {
+               msg = gsm->tx_head;
+               if (gsm->encoding != 0) {
+                       gsm->txframe[0] = GSM1_SOF;
+                       len = gsm_stuff_frame(msg->data,
+                                               gsm->txframe + 1, msg->len);
+                       gsm->txframe[len + 1] = GSM1_SOF;
+                       len += 2;
+               } else {
+                       gsm->txframe[0] = GSM0_SOF;
+                       memcpy(gsm->txframe + 1 , msg->data, msg->len);
+                       gsm->txframe[msg->len + 1] = GSM0_SOF;
+                       len = msg->len + 2;
+               }
+
+               if (debug & 4) {
+                       printk("gsm_data_kick: \n");
+                       hex_packet(gsm->txframe, len);
+               }
+
+               if (gsm->output(gsm, gsm->txframe + skip_sof,
+                                               len - skip_sof) < 0)
+                       break;
+               /* FIXME: Can eliminate one SOF in many more cases */
+               gsm->tx_head = msg->next;
+               if (gsm->tx_head == NULL)
+                       gsm->tx_tail = NULL;
+               gsm->tx_bytes -= msg->len;
+               kfree(msg);
+               /* For a burst of frames skip the extra SOF within the
+                  burst */
+               skip_sof = 1;
+       }
+}
+
+/**
+ *     __gsm_data_queue                -       queue a UI or UIH frame
+ *     @dlci: DLCI sending the data
+ *     @msg: message queued
+ *
+ *     Add data to the transmit queue and try and get stuff moving
+ *     out of the mux tty if not already doing so. The Caller must hold
+ *     the gsm tx lock.
+ */
+
+static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
+{
+       struct gsm_mux *gsm = dlci->gsm;
+       u8 *dp = msg->data;
+       u8 *fcs = dp + msg->len;
+
+       /* Fill in the header */
+       if (gsm->encoding == 0) {
+               if (msg->len < 128)
+                       *--dp = (msg->len << 1) | EA;
+               else {
+                       *--dp = (msg->len >> 6) | EA;
+                       *--dp = (msg->len & 127) << 1;
+               }
+       }
+
+       *--dp = msg->ctrl;
+       if (gsm->initiator)
+               *--dp = (msg->addr << 2) | 2 | EA;
+       else
+               *--dp = (msg->addr << 2) | EA;
+       *fcs = gsm_fcs_add_block(INIT_FCS, dp , msg->data - dp);
+       /* Ugly protocol layering violation */
+       if (msg->ctrl == UI || msg->ctrl == (UI|PF))
+               *fcs = gsm_fcs_add_block(*fcs, msg->data, msg->len);
+       *fcs = 0xFF - *fcs;
+
+       gsm_print_packet("Q> ", msg->addr, gsm->initiator, msg->ctrl,
+                                                       msg->data, msg->len);
+
+       /* Move the header back and adjust the length, also allow for the FCS
+          now tacked on the end */
+       msg->len += (msg->data - dp) + 1;
+       msg->data = dp;
+
+       /* Add to the actual output queue */
+       if (gsm->tx_tail)
+               gsm->tx_tail->next = msg;
+       else
+               gsm->tx_head = msg;
+       gsm->tx_tail = msg;
+       gsm->tx_bytes += msg->len;
+       gsm_data_kick(gsm);
+}
+
+/**
+ *     gsm_data_queue          -       queue a UI or UIH frame
+ *     @dlci: DLCI sending the data
+ *     @msg: message queued
+ *
+ *     Add data to the transmit queue and try and get stuff moving
+ *     out of the mux tty if not already doing so. Take the
+ *     the gsm tx lock and dlci lock.
+ */
+
+static void gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
+       __gsm_data_queue(dlci, msg);
+       spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
+}
+
+/**
+ *     gsm_dlci_data_output    -       try and push data out of a DLCI
+ *     @gsm: mux
+ *     @dlci: the DLCI to pull data from
+ *
+ *     Pull data from a DLCI and send it into the transmit queue if there
+ *     is data. Keep to the MRU of the mux. This path handles the usual tty
+ *     interface which is a byte stream with optional modem data.
+ *
+ *     Caller must hold the tx_lock of the mux.
+ */
+
+static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
+{
+       struct gsm_msg *msg;
+       u8 *dp;
+       int len, size;
+       int h = dlci->adaption - 1;
+
+       len = kfifo_len(dlci->fifo);
+       if (len == 0)
+               return 0;
+
+       /* MTU/MRU count only the data bits */
+       if (len > gsm->mtu)
+               len = gsm->mtu;
+
+       size = len + h;
+
+       msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
+       /* FIXME: need a timer or something to kick this so it can't
+          get stuck with no work outstanding and no buffer free */
+       if (msg == NULL)
+               return -ENOMEM;
+       dp = msg->data;
+       switch (dlci->adaption) {
+       case 1: /* Unstructured */
+               break;
+       case 2: /* Unstructed with modem bits. Always one byte as we never
+                  send inline break data */
+               *dp += gsm_encode_modem(dlci);
+               len--;
+               break;
+       }
+       WARN_ON(kfifo_out_locked(dlci->fifo, dp , len, &dlci->lock) != len);
+       __gsm_data_queue(dlci, msg);
+       /* Bytes of data we used up */
+       return size;
+}
+
+/**
+ *     gsm_dlci_data_output_framed  -  try and push data out of a DLCI
+ *     @gsm: mux
+ *     @dlci: the DLCI to pull data from
+ *
+ *     Pull data from a DLCI and send it into the transmit queue if there
+ *     is data. Keep to the MRU of the mux. This path handles framed data
+ *     queued as skbuffs to the DLCI.
+ *
+ *     Caller must hold the tx_lock of the mux.
+ */
+
+static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
+                                               struct gsm_dlci *dlci)
+{
+       struct gsm_msg *msg;
+       u8 *dp;
+       int len, size;
+       int last = 0, first = 0;
+       int overhead = 0;
+
+       /* One byte per frame is used for B/F flags */
+       if (dlci->adaption == 4)
+               overhead = 1;
+
+       /* dlci->skb is locked by tx_lock */
+       if (dlci->skb == NULL) {
+               dlci->skb = skb_dequeue(&dlci->skb_list);
+               if (dlci->skb == NULL)
+                       return 0;
+               first = 1;
+       }
+       len = dlci->skb->len + overhead;
+
+       /* MTU/MRU count only the data bits */
+       if (len > gsm->mtu) {
+               if (dlci->adaption == 3) {
+                       /* Over long frame, bin it */
+                       kfree_skb(dlci->skb);
+                       dlci->skb = NULL;
+                       return 0;
+               }
+               len = gsm->mtu;
+       } else
+               last = 1;
+
+       size = len + overhead;
+       msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
+
+       /* FIXME: need a timer or something to kick this so it can't
+          get stuck with no work outstanding and no buffer free */
+       if (msg == NULL)
+               return -ENOMEM;
+       dp = msg->data;
+
+       if (dlci->adaption == 4) { /* Interruptible framed (Packetised Data) */
+               /* Flag byte to carry the start/end info */
+               *dp++ = last << 7 | first << 6 | 1;     /* EA */
+               len--;
+       }
+       memcpy(dp, skb_pull(dlci->skb, len), len);
+       __gsm_data_queue(dlci, msg);
+       if (last)
+               dlci->skb = NULL;
+       return size;
+}
+
+/**
+ *     gsm_dlci_data_sweep             -       look for data to send
+ *     @gsm: the GSM mux
+ *
+ *     Sweep the GSM mux channels in priority order looking for ones with
+ *     data to send. We could do with optimising this scan a bit. We aim
+ *     to fill the queue totally or up to TX_THRESH_HI bytes. Once we hit
+ *     TX_THRESH_LO we get called again
+ *
+ *     FIXME: We should round robin between groups and in theory you can
+ *     renegotiate DLCI priorities with optional stuff. Needs optimising.
+ */
+
+static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
+{
+       int len;
+       /* Priority ordering: We should do priority with RR of the groups */
+       int i = 1;
+
+       while (i < NUM_DLCI) {
+               struct gsm_dlci *dlci;
+
+               if (gsm->tx_bytes > TX_THRESH_HI)
+                       break;
+               dlci = gsm->dlci[i];
+               if (dlci == NULL || dlci->constipated) {
+                       i++;
+                       continue;
+               }
+               if (dlci->adaption < 3)
+                       len = gsm_dlci_data_output(gsm, dlci);
+               else
+                       len = gsm_dlci_data_output_framed(gsm, dlci);
+               if (len < 0)
+                       break;
+               /* DLCI empty - try the next */
+               if (len == 0)
+                       i++;
+       }
+}
+
+/**
+ *     gsm_dlci_data_kick      -       transmit if possible
+ *     @dlci: DLCI to kick
+ *
+ *     Transmit data from this DLCI if the queue is empty. We can't rely on
+ *     a tty wakeup except when we filled the pipe so we need to fire off
+ *     new data ourselves in other cases.
+ */
+
+static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
+       /* If we have nothing running then we need to fire up */
+       if (dlci->gsm->tx_bytes == 0)
+               gsm_dlci_data_output(dlci->gsm, dlci);
+       else if (dlci->gsm->tx_bytes < TX_THRESH_LO)
+               gsm_dlci_data_sweep(dlci->gsm);
+       spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
+}
+
+/*
+ *     Control message processing
+ */
+
+
+/**
+ *     gsm_control_reply       -       send a response frame to a control
+ *     @gsm: gsm channel
+ *     @cmd: the command to use
+ *     @data: data to follow encoded info
+ *     @dlen: length of data
+ *
+ *     Encode up and queue a UI/UIH frame containing our response.
+ */
+
+static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data,
+                                       int dlen)
+{
+       struct gsm_msg *msg;
+       msg = gsm_data_alloc(gsm, 0, dlen + 2, gsm->ftype);
+       msg->data[0] = (cmd & 0xFE) << 1 | EA;  /* Clear C/R */
+       msg->data[1] = (dlen << 1) | EA;
+       memcpy(msg->data + 2, data, dlen);
+       gsm_data_queue(gsm->dlci[0], msg);
+}
+
+/**
+ *     gsm_process_modem       -       process received modem status
+ *     @tty: virtual tty bound to the DLCI
+ *     @dlci: DLCI to affect
+ *     @modem: modem bits (full EA)
+ *
+ *     Used when a modem control message or line state inline in adaption
+ *     layer 2 is processed. Sort out the local modem state and throttles
+ */
+
+static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
+                                                       u32 modem)
+{
+       int  mlines = 0;
+       u8 brk = modem >> 6;
+
+       /* Flow control/ready to communicate */
+       if (modem & MDM_FC) {
+               /* Need to throttle our output on this device */
+               dlci->constipated = 1;
+       }
+       if (modem & MDM_RTC) {
+               mlines |= TIOCM_DSR | TIOCM_DTR;
+               dlci->constipated = 0;
+               gsm_dlci_data_kick(dlci);
+       }
+       /* Map modem bits */
+       if (modem & MDM_RTR)
+               mlines |= TIOCM_RTS | TIOCM_CTS;
+       if (modem & MDM_IC)
+               mlines |= TIOCM_RI;
+       if (modem & MDM_DV)
+               mlines |= TIOCM_CD;
+
+       /* Carrier drop -> hangup */
+       if (tty) {
+               if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
+                       if (!(tty->termios->c_cflag & CLOCAL))
+                               tty_hangup(tty);
+               if (brk & 0x01)
+                       tty_insert_flip_char(tty, 0, TTY_BREAK);
+       }
+       dlci->modem_rx = mlines;
+}
+
+/**
+ *     gsm_control_modem       -       modem status received
+ *     @gsm: GSM channel
+ *     @data: data following command
+ *     @clen: command length
+ *
+ *     We have received a modem status control message. This is used by
+ *     the GSM mux protocol to pass virtual modem line status and optionally
+ *     to indicate break signals. Unpack it, convert to Linux representation
+ *     and if need be stuff a break message down the tty.
+ */
+
+static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
+{
+       unsigned int addr = 0;
+       unsigned int modem = 0;
+       struct gsm_dlci *dlci;
+       int len = clen;
+       u8 *dp = data;
+       struct tty_struct *tty;
+
+       while (gsm_read_ea(&addr, *dp++) == 0) {
+               len--;
+               if (len == 0)
+                       return;
+       }
+       /* Must be at least one byte following the EA */
+       len--;
+       if (len <= 0)
+               return;
+
+       addr >>= 1;
+       /* Closed port, or invalid ? */
+       if (addr == 0 || addr >= NUM_DLCI || gsm->dlci[addr] == NULL)
+               return;
+       dlci = gsm->dlci[addr];
+
+       while (gsm_read_ea(&modem, *dp++) == 0) {
+               len--;
+               if (len == 0)
+                       return;
+       }
+       tty = tty_port_tty_get(&dlci->port);
+       gsm_process_modem(tty, dlci, modem);
+       if (tty) {
+               tty_wakeup(tty);
+               tty_kref_put(tty);
+       }
+       gsm_control_reply(gsm, CMD_MSC, data, clen);
+}
+
+/**
+ *     gsm_control_rls         -       remote line status
+ *     @gsm: GSM channel
+ *     @data: data bytes
+ *     @clen: data length
+ *
+ *     The modem sends us a two byte message on the control channel whenever
+ *     it wishes to send us an error state from the virtual link. Stuff
+ *     this into the uplink tty if present
+ */
+
+static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
+{
+       struct tty_struct *tty;
+       unsigned int addr = 0 ;
+       u8 bits;
+       int len = clen;
+       u8 *dp = data;
+
+       while (gsm_read_ea(&addr, *dp++) == 0) {
+               len--;
+               if (len == 0)
+                       return;
+       }
+       /* Must be at least one byte following ea */
+       len--;
+       if (len <= 0)
+               return;
+       addr >>= 1;
+       /* Closed port, or invalid ? */
+       if (addr == 0 || addr >= NUM_DLCI || gsm->dlci[addr] == NULL)
+               return;
+       /* No error ? */
+       bits = *dp;
+       if ((bits & 1) == 0)
+               return;
+       /* See if we have an uplink tty */
+       tty = tty_port_tty_get(&gsm->dlci[addr]->port);
+
+       if (tty) {
+               if (bits & 2)
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               if (bits & 4)
+                       tty_insert_flip_char(tty, 0, TTY_PARITY);
+               if (bits & 8)
+                       tty_insert_flip_char(tty, 0, TTY_FRAME);
+               tty_flip_buffer_push(tty);
+               tty_kref_put(tty);
+       }
+       gsm_control_reply(gsm, CMD_RLS, data, clen);
+}
+
+static void gsm_dlci_begin_close(struct gsm_dlci *dlci);
+
+/**
+ *     gsm_control_message     -       DLCI 0 control processing
+ *     @gsm: our GSM mux
+ *     @command:  the command EA
+ *     @data: data beyond the command/length EAs
+ *     @clen: length
+ *
+ *     Input processor for control messages from the other end of the link.
+ *     Processes the incoming request and queues a response frame or an
+ *     NSC response if not supported
+ */
+
+static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
+                                                       u8 *data, int clen)
+{
+       u8 buf[1];
+       switch (command) {
+       case CMD_CLD: {
+               struct gsm_dlci *dlci = gsm->dlci[0];
+               /* Modem wishes to close down */
+               if (dlci) {
+                       dlci->dead = 1;
+                       gsm->dead = 1;
+                       gsm_dlci_begin_close(dlci);
+               }
+               }
+               break;
+       case CMD_TEST:
+               /* Modem wishes to test, reply with the data */
+               gsm_control_reply(gsm, CMD_TEST, data, clen);
+               break;
+       case CMD_FCON:
+               /* Modem wants us to STFU */
+               gsm->constipated = 1;
+               gsm_control_reply(gsm, CMD_FCON, NULL, 0);
+               break;
+       case CMD_FCOFF:
+               /* Modem can accept data again */
+               gsm->constipated = 0;
+               gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
+               /* Kick the link in case it is idling */
+               gsm_data_kick(gsm);
+               break;
+       case CMD_MSC:
+               /* Out of band modem line change indicator for a DLCI */
+               gsm_control_modem(gsm, data, clen);
+               break;
+       case CMD_RLS:
+               /* Out of band error reception for a DLCI */
+               gsm_control_rls(gsm, data, clen);
+               break;
+       case CMD_PSC:
+               /* Modem wishes to enter power saving state */
+               gsm_control_reply(gsm, CMD_PSC, NULL, 0);
+               break;
+               /* Optional unsupported commands */
+       case CMD_PN:    /* Parameter negotiation */
+       case CMD_RPN:   /* Remote port negotation */
+       case CMD_SNC:   /* Service negotation command */
+       default:
+               /* Reply to bad commands with an NSC */
+               buf[0] = command;
+               gsm_control_reply(gsm, CMD_NSC, buf, 1);
+               break;
+       }
+}
+
+/**
+ *     gsm_control_response    -       process a response to our control
+ *     @gsm: our GSM mux
+ *     @command: the command (response) EA
+ *     @data: data beyond the command/length EA
+ *     @clen: length
+ *
+ *     Process a response to an outstanding command. We only allow a single
+ *     control message in flight so this is fairly easy. All the clean up
+ *     is done by the caller, we just update the fields, flag it as done
+ *     and return
+ */
+
+static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
+                                                       u8 *data, int clen)
+{
+       struct gsm_control *ctrl;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gsm->control_lock, flags);
+
+       ctrl = gsm->pending_cmd;
+       /* Does the reply match our command */
+       command |= 1;
+       if (ctrl != NULL && (command == ctrl->cmd || command == CMD_NSC)) {
+               /* Our command was replied to, kill the retry timer */
+               del_timer(&gsm->t2_timer);
+               gsm->pending_cmd = NULL;
+               /* Rejected by the other end */
+               if (command == CMD_NSC)
+                       ctrl->error = -EOPNOTSUPP;
+               ctrl->done = 1;
+               wake_up(&gsm->event);
+       }
+       spin_unlock_irqrestore(&gsm->control_lock, flags);
+}
+
+/**
+ *     gsm_control_transmit    -       send control packet
+ *     @gsm: gsm mux
+ *     @ctrl: frame to send
+ *
+ *     Send out a pending control command (called under control lock)
+ */
+
+static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl)
+{
+       struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 1,
+                                                       gsm->ftype|PF);
+       if (msg == NULL)
+               return;
+       msg->data[0] = (ctrl->cmd << 1) | 2 | EA;       /* command */
+       memcpy(msg->data + 1, ctrl->data, ctrl->len);
+       gsm_data_queue(gsm->dlci[0], msg);
+}
+
+/**
+ *     gsm_control_retransmit  -       retransmit a control frame
+ *     @data: pointer to our gsm object
+ *
+ *     Called off the T2 timer expiry in order to retransmit control frames
+ *     that have been lost in the system somewhere. The control_lock protects
+ *     us from colliding with another sender or a receive completion event.
+ *     In that situation the timer may still occur in a small window but
+ *     gsm->pending_cmd will be NULL and we just let the timer expire.
+ */
+
+static void gsm_control_retransmit(unsigned long data)
+{
+       struct gsm_mux *gsm = (struct gsm_mux *)data;
+       struct gsm_control *ctrl;
+       unsigned long flags;
+       spin_lock_irqsave(&gsm->control_lock, flags);
+       ctrl = gsm->pending_cmd;
+       if (ctrl) {
+               gsm->cretries--;
+               if (gsm->cretries == 0) {
+                       gsm->pending_cmd = NULL;
+                       ctrl->error = -ETIMEDOUT;
+                       ctrl->done = 1;
+                       spin_unlock_irqrestore(&gsm->control_lock, flags);
+                       wake_up(&gsm->event);
+                       return;
+               }
+               gsm_control_transmit(gsm, ctrl);
+               mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
+       }
+       spin_unlock_irqrestore(&gsm->control_lock, flags);
+}
+
+/**
+ *     gsm_control_send        -       send a control frame on DLCI 0
+ *     @gsm: the GSM channel
+ *     @command: command  to send including CR bit
+ *     @data: bytes of data (must be kmalloced)
+ *     @len: length of the block to send
+ *
+ *     Queue and dispatch a control command. Only one command can be
+ *     active at a time. In theory more can be outstanding but the matching
+ *     gets really complicated so for now stick to one outstanding.
+ */
+
+static struct gsm_control *gsm_control_send(struct gsm_mux *gsm,
+               unsigned int command, u8 *data, int clen)
+{
+       struct gsm_control *ctrl = kzalloc(sizeof(struct gsm_control),
+                                               GFP_KERNEL);
+       unsigned long flags;
+       if (ctrl == NULL)
+               return NULL;
+retry:
+       wait_event(gsm->event, gsm->pending_cmd == NULL);
+       spin_lock_irqsave(&gsm->control_lock, flags);
+       if (gsm->pending_cmd != NULL) {
+               spin_unlock_irqrestore(&gsm->control_lock, flags);
+               goto retry;
+       }
+       ctrl->cmd = command;
+       ctrl->data = data;
+       ctrl->len = clen;
+       gsm->pending_cmd = ctrl;
+       gsm->cretries = gsm->n2;
+       mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
+       gsm_control_transmit(gsm, ctrl);
+       spin_unlock_irqrestore(&gsm->control_lock, flags);
+       return ctrl;
+}
+
+/**
+ *     gsm_control_wait        -       wait for a control to finish
+ *     @gsm: GSM mux
+ *     @control: control we are waiting on
+ *
+ *     Waits for the control to complete or time out. Frees any used
+ *     resources and returns 0 for success, or an error if the remote
+ *     rejected or ignored the request.
+ */
+
+static int gsm_control_wait(struct gsm_mux *gsm, struct gsm_control *control)
+{
+       int err;
+       wait_event(gsm->event, control->done == 1);
+       err = control->error;
+       kfree(control);
+       return err;
+}
+
+
+/*
+ *     DLCI level handling: Needs krefs
+ */
+
+/*
+ *     State transitions and timers
+ */
+
+/**
+ *     gsm_dlci_close          -       a DLCI has closed
+ *     @dlci: DLCI that closed
+ *
+ *     Perform processing when moving a DLCI into closed state. If there
+ *     is an attached tty this is hung up
+ */
+
+static void gsm_dlci_close(struct gsm_dlci *dlci)
+{
+       del_timer(&dlci->t1);
+       if (debug & 8)
+               printk("DLCI %d goes closed.\n", dlci->addr);
+       dlci->state = DLCI_CLOSED;
+       if (dlci->addr != 0) {
+               struct tty_struct  *tty = tty_port_tty_get(&dlci->port);
+               if (tty) {
+                       tty_hangup(tty);
+                       tty_kref_put(tty);
+               }
+               kfifo_reset(dlci->fifo);
+       } else
+               dlci->gsm->dead = 1;
+       wake_up(&dlci->gsm->event);
+       /* A DLCI 0 close is a MUX termination so we need to kick that
+          back to userspace somehow */
+}
+
+/**
+ *     gsm_dlci_open           -       a DLCI has opened
+ *     @dlci: DLCI that opened
+ *
+ *     Perform processing when moving a DLCI into open state.
+ */
+
+static void gsm_dlci_open(struct gsm_dlci *dlci)
+{
+       /* Note that SABM UA .. SABM UA first UA lost can mean that we go
+          open -> open */
+       del_timer(&dlci->t1);
+       /* This will let a tty open continue */
+       dlci->state = DLCI_OPEN;
+       if (debug & 8)
+               printk("DLCI %d goes open.\n", dlci->addr);
+       wake_up(&dlci->gsm->event);
+}
+
+/**
+ *     gsm_dlci_t1             -       T1 timer expiry
+ *     @dlci: DLCI that opened
+ *
+ *     The T1 timer handles retransmits of control frames (essentially of
+ *     SABM and DISC). We resend the command until the retry count runs out
+ *     in which case an opening port goes back to closed and a closing port
+ *     is simply put into closed state (any further frames from the other
+ *     end will get a DM response)
+ */
+
+static void gsm_dlci_t1(unsigned long data)
+{
+       struct gsm_dlci *dlci = (struct gsm_dlci *)data;
+       struct gsm_mux *gsm = dlci->gsm;
+
+       switch (dlci->state) {
+       case DLCI_OPENING:
+               dlci->retries--;
+               if (dlci->retries) {
+                       gsm_command(dlci->gsm, dlci->addr, SABM|PF);
+                       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
+               } else
+                       gsm_dlci_close(dlci);
+               break;
+       case DLCI_CLOSING:
+               dlci->retries--;
+               if (dlci->retries) {
+                       gsm_command(dlci->gsm, dlci->addr, DISC|PF);
+                       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
+               } else
+                       gsm_dlci_close(dlci);
+               break;
+       }
+}
+
+/**
+ *     gsm_dlci_begin_open     -       start channel open procedure
+ *     @dlci: DLCI to open
+ *
+ *     Commence opening a DLCI from the Linux side. We issue SABM messages
+ *     to the modem which should then reply with a UA, at which point we
+ *     will move into open state. Opening is done asynchronously with retry
+ *     running off timers and the responses.
+ */
+
+static void gsm_dlci_begin_open(struct gsm_dlci *dlci)
+{
+       struct gsm_mux *gsm = dlci->gsm;
+       if (dlci->state == DLCI_OPEN || dlci->state == DLCI_OPENING)
+               return;
+       dlci->retries = gsm->n2;
+       dlci->state = DLCI_OPENING;
+       gsm_command(dlci->gsm, dlci->addr, SABM|PF);
+       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
+}
+
+/**
+ *     gsm_dlci_begin_close    -       start channel open procedure
+ *     @dlci: DLCI to open
+ *
+ *     Commence closing a DLCI from the Linux side. We issue DISC messages
+ *     to the modem which should then reply with a UA, at which point we
+ *     will move into closed state. Closing is done asynchronously with retry
+ *     off timers. We may also receive a DM reply from the other end which
+ *     indicates the channel was already closed.
+ */
+
+static void gsm_dlci_begin_close(struct gsm_dlci *dlci)
+{
+       struct gsm_mux *gsm = dlci->gsm;
+       if (dlci->state == DLCI_CLOSED || dlci->state == DLCI_CLOSING)
+               return;
+       dlci->retries = gsm->n2;
+       dlci->state = DLCI_CLOSING;
+       gsm_command(dlci->gsm, dlci->addr, DISC|PF);
+       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
+}
+
+/**
+ *     gsm_dlci_data           -       data arrived
+ *     @dlci: channel
+ *     @data: block of bytes received
+ *     @len: length of received block
+ *
+ *     A UI or UIH frame has arrived which contains data for a channel
+ *     other than the control channel. If the relevant virtual tty is
+ *     open we shovel the bits down it, if not we drop them.
+ */
+
+static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len)
+{
+       /* krefs .. */
+       struct tty_port *port = &dlci->port;
+       struct tty_struct *tty = tty_port_tty_get(port);
+       unsigned int modem = 0;
+
+       if (debug & 16)
+               printk("%d bytes for tty %p\n", len, tty);
+       if (tty) {
+               switch (dlci->adaption)  {
+                       /* Unsupported types */
+                       /* Packetised interruptible data */
+                       case 4:
+                               break;
+                       /* Packetised uininterruptible voice/data */
+                       case 3:
+                               break;
+                       /* Asynchronous serial with line state in each frame */
+                       case 2:
+                               while (gsm_read_ea(&modem, *data++) == 0) {
+                                       len--;
+                                       if (len == 0)
+                                               return;
+                               }
+                               gsm_process_modem(tty, dlci, modem);
+                       /* Line state will go via DLCI 0 controls only */
+                       case 1:
+                       default:
+                               tty_insert_flip_string(tty, data, len);
+                               tty_flip_buffer_push(tty);
+               }
+               tty_kref_put(tty);
+       }
+}
+
+/**
+ *     gsm_dlci_control        -       data arrived on control channel
+ *     @dlci: channel
+ *     @data: block of bytes received
+ *     @len: length of received block
+ *
+ *     A UI or UIH frame has arrived which contains data for DLCI 0 the
+ *     control channel. This should contain a command EA followed by
+ *     control data bytes. The command EA contains a command/response bit
+ *     and we divide up the work accordingly.
+ */
+
+static void gsm_dlci_command(struct gsm_dlci *dlci, u8 *data, int len)
+{
+       /* See what command is involved */
+       unsigned int command = 0;
+       while (len-- > 0) {
+               if (gsm_read_ea(&command, *data++) == 1) {
+                       int clen = *data++;
+                       len--;
+                       /* FIXME: this is properly an EA */
+                       clen >>= 1;
+                       /* Malformed command ? */
+                       if (clen > len)
+                               return;
+                       if (command & 1)
+                               gsm_control_message(dlci->gsm, command,
+                                                               data, clen);
+                       else
+                               gsm_control_response(dlci->gsm, command,
+                                                               data, clen);
+                       return;
+               }
+       }
+}
+
+/*
+ *     Allocate/Free DLCI channels
+ */
+
+/**
+ *     gsm_dlci_alloc          -       allocate a DLCI
+ *     @gsm: GSM mux
+ *     @addr: address of the DLCI
+ *
+ *     Allocate and install a new DLCI object into the GSM mux.
+ *
+ *     FIXME: review locking races
+ */
+
+static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
+{
+       struct gsm_dlci *dlci = kzalloc(sizeof(struct gsm_dlci), GFP_ATOMIC);
+       if (dlci == NULL)
+               return NULL;
+       spin_lock_init(&dlci->lock);
+       dlci->fifo = &dlci->_fifo;
+       if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) {
+               kfree(dlci);
+               return NULL;
+       }
+
+       skb_queue_head_init(&dlci->skb_list);
+       init_timer(&dlci->t1);
+       dlci->t1.function = gsm_dlci_t1;
+       dlci->t1.data = (unsigned long)dlci;
+       tty_port_init(&dlci->port);
+       dlci->port.ops = &gsm_port_ops;
+       dlci->gsm = gsm;
+       dlci->addr = addr;
+       dlci->adaption = gsm->adaption;
+       dlci->state = DLCI_CLOSED;
+       if (addr)
+               dlci->data = gsm_dlci_data;
+       else
+               dlci->data = gsm_dlci_command;
+       gsm->dlci[addr] = dlci;
+       return dlci;
+}
+
+/**
+ *     gsm_dlci_free           -       release DLCI
+ *     @dlci: DLCI to destroy
+ *
+ *     Free up a DLCI. Currently to keep the lifetime rules sane we only
+ *     clean up DLCI objects when the MUX closes rather than as the port
+ *     is closed down on both the tty and mux levels.
+ *
+ *     Can sleep.
+ */
+static void gsm_dlci_free(struct gsm_dlci *dlci)
+{
+       struct tty_struct *tty = tty_port_tty_get(&dlci->port);
+       if (tty) {
+               tty_vhangup(tty);
+               tty_kref_put(tty);
+       }
+       del_timer_sync(&dlci->t1);
+       dlci->gsm->dlci[dlci->addr] = NULL;
+       kfifo_free(dlci->fifo);
+       kfree(dlci);
+}
+
+
+/*
+ *     LAPBish link layer logic
+ */
+
+/**
+ *     gsm_queue               -       a GSM frame is ready to process
+ *     @gsm: pointer to our gsm mux
+ *
+ *     At this point in time a frame has arrived and been demangled from
+ *     the line encoding. All the differences between the encodings have
+ *     been handled below us and the frame is unpacked into the structures.
+ *     The fcs holds the header FCS but any data FCS must be added here.
+ */
+
+static void gsm_queue(struct gsm_mux *gsm)
+{
+       struct gsm_dlci *dlci;
+       u8 cr;
+       int address;
+       /* We have to sneak a look at the packet body to do the FCS.
+          A somewhat layering violation in the spec */
+
+       if ((gsm->control & ~PF) == UI)
+               gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
+       if (gsm->fcs != GOOD_FCS) {
+               gsm->bad_fcs++;
+               if (debug & 4)
+                       printk("BAD FCS %02x\n", gsm->fcs);
+               return;
+       }
+       address = gsm->address >> 1;
+       if (address >= NUM_DLCI)
+               goto invalid;
+
+       cr = gsm->address & 1;          /* C/R bit */
+
+       gsm_print_packet("<--", address, cr, gsm->control, gsm->buf, gsm->len);
+
+       cr ^= 1 - gsm->initiator;       /* Flip so 1 always means command */
+       dlci = gsm->dlci[address];
+
+       switch (gsm->control) {
+       case SABM|PF:
+               if (cr == 0)
+                       goto invalid;
+               if (dlci == NULL)
+                       dlci = gsm_dlci_alloc(gsm, address);
+               if (dlci == NULL)
+                       return;
+               if (dlci->dead)
+                       gsm_response(gsm, address, DM);
+               else {
+                       gsm_response(gsm, address, UA);
+                       gsm_dlci_open(dlci);
+               }
+               break;
+       case DISC|PF:
+               if (cr == 0)
+                       goto invalid;
+               if (dlci == NULL || dlci->state == DLCI_CLOSED) {
+                       gsm_response(gsm, address, DM);
+                       return;
+               }
+               /* Real close complete */
+               gsm_response(gsm, address, UA);
+               gsm_dlci_close(dlci);
+               break;
+       case UA:
+       case UA|PF:
+               if (cr == 0 || dlci == NULL)
+                       break;
+               switch (dlci->state) {
+               case DLCI_CLOSING:
+                       gsm_dlci_close(dlci);
+                       break;
+               case DLCI_OPENING:
+                       gsm_dlci_open(dlci);
+                       break;
+               }
+               break;
+       case DM:        /* DM can be valid unsolicited */
+       case DM|PF:
+               if (cr)
+                       goto invalid;
+               if (dlci == NULL)
+                       return;
+               gsm_dlci_close(dlci);
+               break;
+       case UI:
+       case UI|PF:
+       case UIH:
+       case UIH|PF:
+#if 0
+               if (cr)
+                       goto invalid;
+#endif
+               if (dlci == NULL || dlci->state != DLCI_OPEN) {
+                       gsm_command(gsm, address, DM|PF);
+                       return;
+               }
+               dlci->data(dlci, gsm->buf, gsm->len);
+               break;
+       default:
+               goto invalid;
+       }
+       return;
+invalid:
+       gsm->malformed++;
+       return;
+}
+
+
+/**
+ *     gsm0_receive    -       perform processing for non-transparency
+ *     @gsm: gsm data for this ldisc instance
+ *     @c: character
+ *
+ *     Receive bytes in gsm mode 0
+ */
+
+static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
+{
+       switch (gsm->state) {
+       case GSM_SEARCH:        /* SOF marker */
+               if (c == GSM0_SOF) {
+                       gsm->state = GSM_ADDRESS;
+                       gsm->address = 0;
+                       gsm->len = 0;
+                       gsm->fcs = INIT_FCS;
+               }
+               break;          /* Address EA */
+       case GSM_ADDRESS:
+               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+               if (gsm_read_ea(&gsm->address, c))
+                       gsm->state = GSM_CONTROL;
+               break;
+       case GSM_CONTROL:       /* Control Byte */
+               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+               gsm->control = c;
+               gsm->state = GSM_LEN;
+               break;
+       case GSM_LEN:           /* Length EA */
+               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+               if (gsm_read_ea(&gsm->len, c)) {
+                       if (gsm->len > gsm->mru) {
+                               gsm->bad_size++;
+                               gsm->state = GSM_SEARCH;
+                               break;
+                       }
+                       gsm->count = 0;
+                       gsm->state = GSM_DATA;
+               }
+               break;
+       case GSM_DATA:          /* Data */
+               gsm->buf[gsm->count++] = c;
+               if (gsm->count == gsm->len)
+                       gsm->state = GSM_FCS;
+               break;
+       case GSM_FCS:           /* FCS follows the packet */
+               gsm->fcs = c;
+               gsm_queue(gsm);
+               /* And then back for the next frame */
+               gsm->state = GSM_SEARCH;
+               break;
+       }
+}
+
+/**
+ *     gsm0_receive    -       perform processing for non-transparency
+ *     @gsm: gsm data for this ldisc instance
+ *     @c: character
+ *
+ *     Receive bytes in mode 1 (Advanced option)
+ */
+
+static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
+{
+       if (c == GSM1_SOF) {
+               /* EOF is only valid in frame if we have got to the data state
+                  and received at least one byte (the FCS) */
+               if (gsm->state == GSM_DATA && gsm->count) {
+                       /* Extract the FCS */
+                       gsm->count--;
+                       gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]);
+                       gsm->len = gsm->count;
+                       gsm_queue(gsm);
+                       gsm->state  = GSM_START;
+                       return;
+               }
+               /* Any partial frame was a runt so go back to start */
+               if (gsm->state != GSM_START) {
+                       gsm->malformed++;
+                       gsm->state = GSM_START;
+               }
+               /* A SOF in GSM_START means we are still reading idling or
+                  framing bytes */
+               return;
+       }
+
+       if (c == GSM1_ESCAPE) {
+               gsm->escape = 1;
+               return;
+       }
+
+       /* Only an unescaped SOF gets us out of GSM search */
+       if (gsm->state == GSM_SEARCH)
+               return;
+
+       if (gsm->escape) {
+               c ^= GSM1_ESCAPE_BITS;
+               gsm->escape = 0;
+       }
+       switch (gsm->state) {
+       case GSM_START:         /* First byte after SOF */
+               gsm->address = 0;
+               gsm->state = GSM_ADDRESS;
+               gsm->fcs = INIT_FCS;
+               /* Drop through */
+       case GSM_ADDRESS:       /* Address continuation */
+               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+               if (gsm_read_ea(&gsm->address, c))
+                       gsm->state = GSM_CONTROL;
+               break;
+       case GSM_CONTROL:       /* Control Byte */
+               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+               gsm->control = c;
+               gsm->count = 0;
+               gsm->state = GSM_DATA;
+               break;
+       case GSM_DATA:          /* Data */
+               if (gsm->count > gsm->mru ) {   /* Allow one for the FCS */
+                       gsm->state = GSM_OVERRUN;
+                       gsm->bad_size++;
+               } else
+                       gsm->buf[gsm->count++] = c;
+               break;
+       case GSM_OVERRUN:       /* Over-long - eg a dropped SOF */
+               break;
+       }
+}
+
+/**
+ *     gsm_error               -       handle tty error
+ *     @gsm: ldisc data
+ *     @data: byte received (may be invalid)
+ *     @flag: error received
+ *
+ *     Handle an error in the receipt of data for a frame. Currently we just
+ *     go back to hunting for a SOF.
+ *
+ *     FIXME: better diagnostics ?
+ */
+
+static void gsm_error(struct gsm_mux *gsm,
+                               unsigned char data, unsigned char flag)
+{
+       gsm->state = GSM_SEARCH;
+       gsm->io_error++;
+}
+
+/**
+ *     gsm_cleanup_mux         -       generic GSM protocol cleanup
+ *     @gsm: our mux
+ *
+ *     Clean up the bits of the mux which are the same for all framing
+ *     protocols. Remove the mux from the mux table, stop all the timers
+ *     and then shut down each device hanging up the channels as we go.
+ */
+
+void gsm_cleanup_mux(struct gsm_mux *gsm)
+{
+       int i;
+       struct gsm_dlci *dlci = gsm->dlci[0];
+       struct gsm_msg *txq;
+
+       gsm->dead = 1;
+
+       spin_lock(&gsm_mux_lock);
+       for (i = 0; i < MAX_MUX; i++) {
+               if (gsm_mux[i] == gsm) {
+                       gsm_mux[i] = NULL;
+                       break;
+               }
+       }
+       spin_unlock(&gsm_mux_lock);
+       WARN_ON(i == MAX_MUX);
+
+       del_timer_sync(&gsm->t2_timer);
+       /* Now we are sure T2 has stopped */
+       if (dlci) {
+               dlci->dead = 1;
+               gsm_dlci_begin_close(dlci);
+               wait_event_interruptible(gsm->event,
+                                       dlci->state == DLCI_CLOSED);
+       }
+       /* Free up any link layer users */
+       for (i = 0; i < NUM_DLCI; i++)
+               if (gsm->dlci[i])
+                       gsm_dlci_free(gsm->dlci[i]);
+       /* Now wipe the queues */
+       for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) {
+               gsm->tx_head = txq->next;
+               kfree(txq);
+       }
+       gsm->tx_tail = NULL;
+}
+EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
+
+/**
+ *     gsm_activate_mux        -       generic GSM setup
+ *     @gsm: our mux
+ *
+ *     Set up the bits of the mux which are the same for all framing
+ *     protocols. Add the mux to the mux table so it can be opened and
+ *     finally kick off connecting to DLCI 0 on the modem.
+ */
+
+int gsm_activate_mux(struct gsm_mux *gsm)
+{
+       struct gsm_dlci *dlci;
+       int i = 0;
+
+       init_timer(&gsm->t2_timer);
+       gsm->t2_timer.function = gsm_control_retransmit;
+       gsm->t2_timer.data = (unsigned long)gsm;
+       init_waitqueue_head(&gsm->event);
+       spin_lock_init(&gsm->control_lock);
+       spin_lock_init(&gsm->tx_lock);
+
+       if (gsm->encoding == 0)
+               gsm->receive = gsm0_receive;
+       else
+               gsm->receive = gsm1_receive;
+       gsm->error = gsm_error;
+
+       spin_lock(&gsm_mux_lock);
+       for (i = 0; i < MAX_MUX; i++) {
+               if (gsm_mux[i] == NULL) {
+                       gsm_mux[i] = gsm;
+                       break;
+               }
+       }
+       spin_unlock(&gsm_mux_lock);
+       if (i == MAX_MUX)
+               return -EBUSY;
+
+       dlci = gsm_dlci_alloc(gsm, 0);
+       if (dlci == NULL)
+               return -ENOMEM;
+       gsm->dead = 0;          /* Tty opens are now permissible */
+       return 0;
+}
+EXPORT_SYMBOL_GPL(gsm_activate_mux);
+
+/**
+ *     gsm_free_mux            -       free up a mux
+ *     @mux: mux to free
+ *
+ *     Dispose of allocated resources for a dead mux. No refcounting
+ *     at present so the mux must be truely dead.
+ */
+void gsm_free_mux(struct gsm_mux *gsm)
+{
+       kfree(gsm->txframe);
+       kfree(gsm->buf);
+       kfree(gsm);
+}
+EXPORT_SYMBOL_GPL(gsm_free_mux);
+
+/**
+ *     gsm_alloc_mux           -       allocate a mux
+ *
+ *     Creates a new mux ready for activation.
+ */
+
+struct gsm_mux *gsm_alloc_mux(void)
+{
+       struct gsm_mux *gsm = kzalloc(sizeof(struct gsm_mux), GFP_KERNEL);
+       if (gsm == NULL)
+               return NULL;
+       gsm->buf = kmalloc(MAX_MRU + 1, GFP_KERNEL);
+       if (gsm->buf == NULL) {
+               kfree(gsm);
+               return NULL;
+       }
+       gsm->txframe = kmalloc(2 * MAX_MRU + 2, GFP_KERNEL);
+       if (gsm->txframe == NULL) {
+               kfree(gsm->buf);
+               kfree(gsm);
+               return NULL;
+       }
+       spin_lock_init(&gsm->lock);
+
+       gsm->t1 = T1;
+       gsm->t2 = T2;
+       gsm->n2 = N2;
+       gsm->ftype = UIH;
+       gsm->initiator = 0;
+       gsm->adaption = 1;
+       gsm->encoding = 1;
+       gsm->mru = 64;  /* Default to encoding 1 so these should be 64 */
+       gsm->mtu = 64;
+       gsm->dead = 1;  /* Avoid early tty opens */
+
+       return gsm;
+}
+EXPORT_SYMBOL_GPL(gsm_alloc_mux);
+
+
+
+
+/**
+ *     gsmld_output            -       write to link
+ *     @gsm: our mux
+ *     @data: bytes to output
+ *     @len: size
+ *
+ *     Write a block of data from the GSM mux to the data channel. This
+ *     will eventually be serialized from above but at the moment isn't.
+ */
+
+static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
+{
+       if (tty_write_room(gsm->tty) < len) {
+               set_bit(TTY_DO_WRITE_WAKEUP, &gsm->tty->flags);
+               return -ENOSPC;
+       }
+       if (debug & 4) {
+               printk("-->%d bytes out\n", len);
+               hex_packet(data, len);
+       }
+       gsm->tty->ops->write(gsm->tty, data, len);
+       return len;
+}
+
+/**
+ *     gsmld_attach_gsm        -       mode set up
+ *     @tty: our tty structure
+ *     @gsm: our mux
+ *
+ *     Set up the MUX for basic mode and commence connecting to the
+ *     modem. Currently called from the line discipline set up but
+ *     will need moving to an ioctl path.
+ */
+
+static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
+{
+       int ret;
+
+       gsm->tty = tty_kref_get(tty);
+       gsm->output = gsmld_output;
+       ret =  gsm_activate_mux(gsm);
+       if (ret != 0)
+               tty_kref_put(gsm->tty);
+       return ret;
+}
+
+
+/**
+ *     gsmld_detach_gsm        -       stop doing 0710 mux
+ *     @tty: tty atttached to the mux
+ *     @gsm: mux
+ *
+ *     Shutdown and then clean up the resources used by the line discipline
+ */
+
+static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
+{
+       WARN_ON(tty != gsm->tty);
+       gsm_cleanup_mux(gsm);
+       tty_kref_put(gsm->tty);
+       gsm->tty = NULL;
+}
+
+static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                             char *fp, int count)
+{
+       struct gsm_mux *gsm = tty->disc_data;
+       const unsigned char *dp;
+       char *f;
+       int i;
+       char buf[64];
+       char flags;
+
+       if (debug & 4) {
+               printk("Inbytes %dd\n", count);
+               hex_packet(cp, count);
+       }
+
+       for (i = count, dp = cp, f = fp; i; i--, dp++) {
+               flags = *f++;
+               switch (flags) {
+               case TTY_NORMAL:
+                       gsm->receive(gsm, *dp);
+                       break;
+               case TTY_OVERRUN:
+               case TTY_BREAK:
+               case TTY_PARITY:
+               case TTY_FRAME:
+                       gsm->error(gsm, *dp, flags);
+                       break;
+               default:
+                       printk(KERN_ERR "%s: unknown flag %d\n",
+                              tty_name(tty, buf), flags);
+                       break;
+               }
+       }
+       /* FASYNC if needed ? */
+       /* If clogged call tty_throttle(tty); */
+}
+
+/**
+ *     gsmld_chars_in_buffer   -       report available bytes
+ *     @tty: tty device
+ *
+ *     Report the number of characters buffered to be delivered to user
+ *     at this instant in time.
+ *
+ *     Locking: gsm lock
+ */
+
+static ssize_t gsmld_chars_in_buffer(struct tty_struct *tty)
+{
+       return 0;
+}
+
+/**
+ *     gsmld_flush_buffer      -       clean input queue
+ *     @tty:   terminal device
+ *
+ *     Flush the input buffer. Called when the line discipline is
+ *     being closed, when the tty layer wants the buffer flushed (eg
+ *     at hangup).
+ */
+
+static void gsmld_flush_buffer(struct tty_struct *tty)
+{
+}
+
+/**
+ *     gsmld_close             -       close the ldisc for this tty
+ *     @tty: device
+ *
+ *     Called from the terminal layer when this line discipline is
+ *     being shut down, either because of a close or becsuse of a
+ *     discipline change. The function will not be called while other
+ *     ldisc methods are in progress.
+ */
+
+static void gsmld_close(struct tty_struct *tty)
+{
+       struct gsm_mux *gsm = tty->disc_data;
+
+       gsmld_detach_gsm(tty, gsm);
+
+       gsmld_flush_buffer(tty);
+       /* Do other clean up here */
+       gsm_free_mux(gsm);
+}
+
+/**
+ *     gsmld_open              -       open an ldisc
+ *     @tty: terminal to open
+ *
+ *     Called when this line discipline is being attached to the
+ *     terminal device. Can sleep. Called serialized so that no
+ *     other events will occur in parallel. No further open will occur
+ *     until a close.
+ */
+
+static int gsmld_open(struct tty_struct *tty)
+{
+       struct gsm_mux *gsm;
+
+       if (tty->ops->write == NULL)
+               return -EINVAL;
+
+       /* Attach our ldisc data */
+       gsm = gsm_alloc_mux();
+       if (gsm == NULL)
+               return -ENOMEM;
+
+       tty->disc_data = gsm;
+       tty->receive_room = 65536;
+
+       /* Attach the initial passive connection */
+       gsm->encoding = 1;
+       return gsmld_attach_gsm(tty, gsm);
+}
+
+/**
+ *     gsmld_write_wakeup      -       asynchronous I/O notifier
+ *     @tty: tty device
+ *
+ *     Required for the ptys, serial driver etc. since processes
+ *     that attach themselves to the master and rely on ASYNC
+ *     IO must be woken up
+ */
+
+static void gsmld_write_wakeup(struct tty_struct *tty)
+{
+       struct gsm_mux *gsm = tty->disc_data;
+       unsigned long flags;
+
+       /* Queue poll */
+       clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       gsm_data_kick(gsm);
+       if (gsm->tx_bytes < TX_THRESH_LO) {
+               spin_lock_irqsave(&gsm->tx_lock, flags);
+               gsm_dlci_data_sweep(gsm);
+               spin_unlock_irqrestore(&gsm->tx_lock, flags);
+       }
+}
+
+/**
+ *     gsmld_read              -       read function for tty
+ *     @tty: tty device
+ *     @file: file object
+ *     @buf: userspace buffer pointer
+ *     @nr: size of I/O
+ *
+ *     Perform reads for the line discipline. We are guaranteed that the
+ *     line discipline will not be closed under us but we may get multiple
+ *     parallel readers and must handle this ourselves. We may also get
+ *     a hangup. Always called in user context, may sleep.
+ *
+ *     This code must be sure never to sleep through a hangup.
+ */
+
+static ssize_t gsmld_read(struct tty_struct *tty, struct file *file,
+                        unsigned char __user *buf, size_t nr)
+{
+       return -EOPNOTSUPP;
+}
+
+/**
+ *     gsmld_write             -       write function for tty
+ *     @tty: tty device
+ *     @file: file object
+ *     @buf: userspace buffer pointer
+ *     @nr: size of I/O
+ *
+ *     Called when the owner of the device wants to send a frame
+ *     itself (or some other control data). The data is transferred
+ *     as-is and must be properly framed and checksummed as appropriate
+ *     by userspace. Frames are either sent whole or not at all as this
+ *     avoids pain user side.
+ */
+
+static ssize_t gsmld_write(struct tty_struct *tty, struct file *file,
+                          const unsigned char *buf, size_t nr)
+{
+       int space = tty_write_room(tty);
+       if (space >= nr)
+               return tty->ops->write(tty, buf, nr);
+       set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       return -ENOBUFS;
+}
+
+/**
+ *     gsmld_poll              -       poll method for N_GSM0710
+ *     @tty: terminal device
+ *     @file: file accessing it
+ *     @wait: poll table
+ *
+ *     Called when the line discipline is asked to poll() for data or
+ *     for special events. This code is not serialized with respect to
+ *     other events save open/close.
+ *
+ *     This code must be sure never to sleep through a hangup.
+ *     Called without the kernel lock held - fine
+ */
+
+static unsigned int gsmld_poll(struct tty_struct *tty, struct file *file,
+                                                       poll_table *wait)
+{
+       unsigned int mask = 0;
+       struct gsm_mux *gsm = tty->disc_data;
+
+       poll_wait(file, &tty->read_wait, wait);
+       poll_wait(file, &tty->write_wait, wait);
+       if (tty_hung_up_p(file))
+               mask |= POLLHUP;
+       if (!tty_is_writelocked(tty) && tty_write_room(tty) > 0)
+               mask |= POLLOUT | POLLWRNORM;
+       if (gsm->dead)
+               mask |= POLLHUP;
+       return mask;
+}
+
+static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
+                                                       struct gsm_config *c)
+{
+       int need_close = 0;
+       int need_restart = 0;
+
+       /* Stuff we don't support yet - UI or I frame transport, windowing */
+       if ((c->adaption !=1 && c->adaption != 2) || c->k)
+               return -EOPNOTSUPP;
+       /* Check the MRU/MTU range looks sane */
+       if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8)
+               return -EINVAL;
+       if (c->n2 < 3)
+               return -EINVAL;
+       if (c->encapsulation > 1)       /* Basic, advanced, no I */
+               return -EINVAL;
+       if (c->initiator > 1)
+               return -EINVAL;
+       if (c->i == 0 || c->i > 2)      /* UIH and UI only */
+               return -EINVAL;
+       /*
+        *      See what is needed for reconfiguration
+        */
+
+       /* Timing fields */
+       if (c->t1 != 0 && c->t1 != gsm->t1)
+               need_restart = 1;
+       if (c->t2 != 0 && c->t2 != gsm->t2)
+               need_restart = 1;
+       if (c->encapsulation != gsm->encoding)
+               need_restart = 1;
+       if (c->adaption != gsm->adaption)
+               need_restart = 1;
+       /* Requires care */
+       if (c->initiator != gsm->initiator)
+               need_close = 1;
+       if (c->mru != gsm->mru)
+               need_restart = 1;
+       if (c->mtu != gsm->mtu)
+               need_restart = 1;
+
+       /*
+        *      Close down what is needed, restart and initiate the new
+        *      configuration
+        */
+
+       if (need_close || need_restart) {
+               gsm_dlci_begin_close(gsm->dlci[0]);
+               /* This will timeout if the link is down due to N2 expiring */
+               wait_event_interruptible(gsm->event,
+                               gsm->dlci[0]->state == DLCI_CLOSED);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
+       if (need_restart)
+               gsm_cleanup_mux(gsm);
+
+       gsm->initiator = c->initiator;
+       gsm->mru = c->mru;
+       gsm->encoding = c->encapsulation;
+       gsm->adaption = c->adaption;
+
+       if (c->i == 1)
+               gsm->ftype = UIH;
+       else if (c->i == 2)
+               gsm->ftype = UI;
+
+       if (c->t1)
+               gsm->t1 = c->t1;
+       if (c->t2)
+               gsm->t2 = c->t2;
+
+       /* FIXME: We need to separate activation/deactivation from adding
+          and removing from the mux array */
+       if (need_restart)
+               gsm_activate_mux(gsm);
+       if (gsm->initiator && need_close)
+               gsm_dlci_begin_open(gsm->dlci[0]);
+       return 0;
+}
+
+static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       struct gsm_config c;
+       struct gsm_mux *gsm = tty->disc_data;
+
+       switch (cmd) {
+       case GSMIOC_GETCONF:
+               memset(&c, 0, sizeof(c));
+               c.adaption = gsm->adaption;
+               c.encapsulation = gsm->encoding;
+               c.initiator = gsm->initiator;
+               c.t1 = gsm->t1;
+               c.t2 = gsm->t2;
+               c.t3 = 0;       /* Not supported */
+               c.n2 = gsm->n2;
+               if (gsm->ftype == UIH)
+                       c.i = 1;
+               else
+                       c.i = 2;
+               printk("Ftype %d i %d\n", gsm->ftype, c.i);
+               c.mru = gsm->mru;
+               c.mtu = gsm->mtu;
+               c.k = 0;
+               if (copy_to_user((void *)arg, &c, sizeof(c)))
+                       return -EFAULT;
+               return 0;
+       case GSMIOC_SETCONF:
+               if (copy_from_user(&c, (void *)arg, sizeof(c)))
+                       return -EFAULT;
+               return gsmld_config(tty, gsm, &c);
+       default:
+               return n_tty_ioctl_helper(tty, file, cmd, arg);
+       }
+}
+
+
+/* Line discipline for real tty */
+struct tty_ldisc_ops tty_ldisc_packet = {
+       .owner           = THIS_MODULE,
+       .magic           = TTY_LDISC_MAGIC,
+       .name            = "n_gsm",
+       .open            = gsmld_open,
+       .close           = gsmld_close,
+       .flush_buffer    = gsmld_flush_buffer,
+       .chars_in_buffer = gsmld_chars_in_buffer,
+       .read            = gsmld_read,
+       .write           = gsmld_write,
+       .ioctl           = gsmld_ioctl,
+       .poll            = gsmld_poll,
+       .receive_buf     = gsmld_receive_buf,
+       .write_wakeup    = gsmld_write_wakeup
+};
+
+/*
+ *     Virtual tty side
+ */
+
+#define TX_SIZE                512
+
+static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
+{
+       u8 modembits[5];
+       struct gsm_control *ctrl;
+       int len = 2;
+
+       if (brk)
+               len++;
+
+       modembits[0] = len << 1 | EA;           /* Data bytes */
+       modembits[1] = dlci->addr << 2 | 3;     /* DLCI, EA, 1 */
+       modembits[2] = gsm_encode_modem(dlci) << 1 | EA;
+       if (brk)
+               modembits[3] = brk << 4 | 2 | EA;       /* Valid, EA */
+       ctrl = gsm_control_send(dlci->gsm, CMD_MSC, modembits, len + 1);
+       if (ctrl == NULL)
+               return -ENOMEM;
+       return gsm_control_wait(dlci->gsm, ctrl);
+}
+
+static int gsm_carrier_raised(struct tty_port *port)
+{
+       struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
+       /* Not yet open so no carrier info */
+       if (dlci->state != DLCI_OPEN)
+               return 0;
+       if (debug & 2)
+               return 1;
+       return dlci->modem_rx & TIOCM_CD;
+}
+
+static void gsm_dtr_rts(struct tty_port *port, int onoff)
+{
+       struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
+       unsigned int modem_tx = dlci->modem_tx;
+       if (onoff)
+               modem_tx |= TIOCM_DTR | TIOCM_RTS;
+       else
+               modem_tx &= ~(TIOCM_DTR | TIOCM_RTS);
+       if (modem_tx != dlci->modem_tx) {
+               dlci->modem_tx = modem_tx;
+               gsmtty_modem_update(dlci, 0);
+       }
+}
+
+static const struct tty_port_operations gsm_port_ops = {
+       .carrier_raised = gsm_carrier_raised,
+       .dtr_rts = gsm_dtr_rts,
+};
+
+
+static int gsmtty_open(struct tty_struct *tty, struct file *filp)
+{
+       struct gsm_mux *gsm;
+       struct gsm_dlci *dlci;
+       struct tty_port *port;
+       unsigned int line = tty->index;
+       unsigned int mux = line >> 6;
+
+       line = line & 0x3F;
+
+       if (mux >= MAX_MUX)
+               return -ENXIO;
+       /* FIXME: we need to lock gsm_mux for lifetimes of ttys eventually */
+       if (gsm_mux[mux] == NULL)
+               return -EUNATCH;
+       if (line == 0 || line > 61)     /* 62/63 reserved */
+               return -ECHRNG;
+       gsm = gsm_mux[mux];
+       if (gsm->dead)
+               return -EL2HLT;
+       dlci = gsm->dlci[line];
+       if (dlci == NULL)
+               dlci = gsm_dlci_alloc(gsm, line);
+       if (dlci == NULL)
+               return -ENOMEM;
+       port = &dlci->port;
+       port->count++;
+       tty->driver_data = dlci;
+       tty_port_tty_set(port, tty);
+
+       dlci->modem_rx = 0;
+       /* We could in theory open and close before we wait - eg if we get
+          a DM straight back. This is ok as that will have caused a hangup */
+       set_bit(ASYNCB_INITIALIZED, &port->flags);
+       /* Start sending off SABM messages */
+       gsm_dlci_begin_open(dlci);
+       /* And wait for virtual carrier */
+       return tty_port_block_til_ready(port, tty, filp);
+}
+
+static void gsmtty_close(struct tty_struct *tty, struct file *filp)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       if (dlci == NULL)
+               return;
+       if (tty_port_close_start(&dlci->port, tty, filp) == 0)
+               return;
+       gsm_dlci_begin_close(dlci);
+       tty_port_close_end(&dlci->port, tty);
+       tty_port_tty_set(&dlci->port, NULL);
+}
+
+static void gsmtty_hangup(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       tty_port_hangup(&dlci->port);
+       gsm_dlci_begin_close(dlci);
+}
+
+static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf,
+                                                                   int len)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       /* Stuff the bytes into the fifo queue */
+       int sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock);
+       /* Need to kick the channel */
+       gsm_dlci_data_kick(dlci);
+       return sent;
+}
+
+static int gsmtty_write_room(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       return TX_SIZE - kfifo_len(dlci->fifo);
+}
+
+static int gsmtty_chars_in_buffer(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       return kfifo_len(dlci->fifo);
+}
+
+static void gsmtty_flush_buffer(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       /* Caution needed: If we implement reliable transport classes
+          then the data being transmitted can't simply be junked once
+          it has first hit the stack. Until then we can just blow it
+          away */
+       kfifo_reset(dlci->fifo);
+       /* Need to unhook this DLCI from the transmit queue logic */
+}
+
+static void gsmtty_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+       /* The FIFO handles the queue so the kernel will do the right
+          thing waiting on chars_in_buffer before calling us. No work
+          to do here */
+}
+
+static int gsmtty_tiocmget(struct tty_struct *tty, struct file *filp)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       return dlci->modem_rx;
+}
+
+static int gsmtty_tiocmset(struct tty_struct *tty, struct file *filp,
+       unsigned int set, unsigned int clear)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       unsigned int modem_tx = dlci->modem_tx;
+
+       modem_tx &= clear;
+       modem_tx |= set;
+
+       if (modem_tx != dlci->modem_tx) {
+               dlci->modem_tx = modem_tx;
+               return gsmtty_modem_update(dlci, 0);
+       }
+       return 0;
+}
+
+
+static int gsmtty_ioctl(struct tty_struct *tty, struct file *filp,
+                       unsigned int cmd, unsigned long arg)
+{
+       return -ENOIOCTLCMD;
+}
+
+static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
+{
+       /* For the moment its fixed. In actual fact the speed information
+          for the virtual channel can be propogated in both directions by
+          the RPN control message. This however rapidly gets nasty as we
+          then have to remap modem signals each way according to whether
+          our virtual cable is null modem etc .. */
+       tty_termios_copy_hw(tty->termios, old);
+}
+
+static void gsmtty_throttle(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       if (tty->termios->c_cflag & CRTSCTS)
+               dlci->modem_tx &= ~TIOCM_DTR;
+       dlci->throttled = 1;
+       /* Send an MSC with DTR cleared */
+       gsmtty_modem_update(dlci, 0);
+}
+
+static void gsmtty_unthrottle(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       if (tty->termios->c_cflag & CRTSCTS)
+               dlci->modem_tx |= TIOCM_DTR;
+       dlci->throttled = 0;
+       /* Send an MSC with DTR set */
+       gsmtty_modem_update(dlci, 0);
+}
+
+static int gsmtty_break_ctl(struct tty_struct *tty, int state)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       int encode = 0; /* Off */
+
+       if (state == -1)        /* "On indefinitely" - we can't encode this
+                                   properly */
+               encode = 0x0F;
+       else if (state > 0) {
+               encode = state / 200;   /* mS to encoding */
+               if (encode > 0x0F)
+                       encode = 0x0F;  /* Best effort */
+       }
+       return gsmtty_modem_update(dlci, encode);
+}
+
+static struct tty_driver *gsm_tty_driver;
+
+/* Virtual ttys for the demux */
+static const struct tty_operations gsmtty_ops = {
+       .open                   = gsmtty_open,
+       .close                  = gsmtty_close,
+       .write                  = gsmtty_write,
+       .write_room             = gsmtty_write_room,
+       .chars_in_buffer        = gsmtty_chars_in_buffer,
+       .flush_buffer           = gsmtty_flush_buffer,
+       .ioctl                  = gsmtty_ioctl,
+       .throttle               = gsmtty_throttle,
+       .unthrottle             = gsmtty_unthrottle,
+       .set_termios            = gsmtty_set_termios,
+       .hangup                 = gsmtty_hangup,
+       .wait_until_sent        = gsmtty_wait_until_sent,
+       .tiocmget               = gsmtty_tiocmget,
+       .tiocmset               = gsmtty_tiocmset,
+       .break_ctl              = gsmtty_break_ctl,
+};
+
+
+
+static int __init gsm_init(void)
+{
+       /* Fill in our line protocol discipline, and register it */
+       int status = tty_register_ldisc(N_GSM0710, &tty_ldisc_packet);
+       if (status != 0) {
+               printk(KERN_ERR "n_gsm: can't register line discipline (err = %d)\n", status);
+               return status;
+       }
+
+       gsm_tty_driver = alloc_tty_driver(256);
+       if (!gsm_tty_driver) {
+               tty_unregister_ldisc(N_GSM0710);
+               printk(KERN_ERR "gsm_init: tty allocation failed.\n");
+               return -EINVAL;
+       }
+       gsm_tty_driver->owner   = THIS_MODULE;
+       gsm_tty_driver->driver_name     = "gsmtty";
+       gsm_tty_driver->name            = "gsmtty";
+       gsm_tty_driver->major           = 0;    /* Dynamic */
+       gsm_tty_driver->minor_start     = 0;
+       gsm_tty_driver->type            = TTY_DRIVER_TYPE_SERIAL;
+       gsm_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+       gsm_tty_driver->flags   = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
+                                                       | TTY_DRIVER_HARDWARE_BREAK;
+       gsm_tty_driver->init_termios    = tty_std_termios;
+       /* Fixme */
+       gsm_tty_driver->init_termios.c_lflag &= ~ECHO;
+       tty_set_operations(gsm_tty_driver, &gsmtty_ops);
+
+       spin_lock_init(&gsm_mux_lock);
+
+       if (tty_register_driver(gsm_tty_driver)) {
+               put_tty_driver(gsm_tty_driver);
+               tty_unregister_ldisc(N_GSM0710);
+               printk(KERN_ERR "gsm_init: tty registration failed.\n");
+               return -EBUSY;
+       }
+       printk(KERN_INFO "gsm_init: loaded as %d,%d.\n", gsm_tty_driver->major, gsm_tty_driver->minor_start);
+       return 0;
+}
+
+static void __exit gsm_exit(void)
+{
+       int status = tty_unregister_ldisc(N_GSM0710);
+       if (status != 0)
+               printk(KERN_ERR "n_gsm: can't unregister line discipline (err = %d)\n", status);
+       tty_unregister_driver(gsm_tty_driver);
+       put_tty_driver(gsm_tty_driver);
+       printk(KERN_INFO "gsm_init: unloaded.\n");
+}
+
+module_init(gsm_init);
+module_exit(gsm_exit);
+
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_LDISC(N_GSM0710);
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
new file mode 100644 (file)
index 0000000..47d3228
--- /dev/null
@@ -0,0 +1,1007 @@
+/* generic HDLC line discipline for Linux
+ *
+ * Written by Paul Fulghum paulkf@microgate.com
+ * for Microgate Corporation
+ *
+ * Microgate and SyncLink are registered trademarks of Microgate Corporation
+ *
+ * Adapted from ppp.c, written by Michael Callahan <callahan@maths.ox.ac.uk>,
+ *     Al Longyear <longyear@netcom.com>,
+ *     Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
+ *
+ * Original release 01/11/99
+ *
+ * This code is released under the GNU General Public License (GPL)
+ *
+ * This module implements the tty line discipline N_HDLC for use with
+ * tty device drivers that support bit-synchronous HDLC communications.
+ *
+ * All HDLC data is frame oriented which means:
+ *
+ * 1. tty write calls represent one complete transmit frame of data
+ *    The device driver should accept the complete frame or none of 
+ *    the frame (busy) in the write method. Each write call should have
+ *    a byte count in the range of 2-65535 bytes (2 is min HDLC frame
+ *    with 1 addr byte and 1 ctrl byte). The max byte count of 65535
+ *    should include any crc bytes required. For example, when using
+ *    CCITT CRC32, 4 crc bytes are required, so the maximum size frame
+ *    the application may transmit is limited to 65531 bytes. For CCITT
+ *    CRC16, the maximum application frame size would be 65533.
+ *
+ *
+ * 2. receive callbacks from the device driver represents
+ *    one received frame. The device driver should bypass
+ *    the tty flip buffer and call the line discipline receive
+ *    callback directly to avoid fragmenting or concatenating
+ *    multiple frames into a single receive callback.
+ *
+ *    The HDLC line discipline queues the receive frames in separate
+ *    buffers so complete receive frames can be returned by the
+ *    tty read calls.
+ *
+ * 3. tty read calls returns an entire frame of data or nothing.
+ *    
+ * 4. all send and receive data is considered raw. No processing
+ *    or translation is performed by the line discipline, regardless
+ *    of the tty flags
+ *
+ * 5. When line discipline is queried for the amount of receive
+ *    data available (FIOC), 0 is returned if no data available,
+ *    otherwise the count of the next available frame is returned.
+ *    (instead of the sum of all received frame counts).
+ *
+ * These conventions allow the standard tty programming interface
+ * to be used for synchronous HDLC applications when used with
+ * this line discipline (or another line discipline that is frame
+ * oriented such as N_PPP).
+ *
+ * The SyncLink driver (synclink.c) implements both asynchronous
+ * (using standard line discipline N_TTY) and synchronous HDLC
+ * (using N_HDLC) communications, with the latter using the above
+ * conventions.
+ *
+ * This implementation is very basic and does not maintain
+ * any statistics. The main point is to enforce the raw data
+ * and frame orientation of HDLC communications.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define HDLC_MAGIC 0x239e
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+
+#undef VERSION
+#define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
+
+#include <linux/poll.h>
+#include <linux/in.h>
+#include <linux/ioctl.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/smp_lock.h>
+#include <linux/string.h>      /* used in new tty drivers */
+#include <linux/signal.h>      /* used in new tty drivers */
+#include <linux/if.h>
+#include <linux/bitops.h>
+
+#include <asm/system.h>
+#include <asm/termios.h>
+#include <asm/uaccess.h>
+
+/*
+ * Buffers for individual HDLC frames
+ */
+#define MAX_HDLC_FRAME_SIZE 65535 
+#define DEFAULT_RX_BUF_COUNT 10
+#define MAX_RX_BUF_COUNT 60
+#define DEFAULT_TX_BUF_COUNT 3
+
+struct n_hdlc_buf {
+       struct n_hdlc_buf *link;
+       int               count;
+       char              buf[1];
+};
+
+#define        N_HDLC_BUF_SIZE (sizeof(struct n_hdlc_buf) + maxframe)
+
+struct n_hdlc_buf_list {
+       struct n_hdlc_buf *head;
+       struct n_hdlc_buf *tail;
+       int               count;
+       spinlock_t        spinlock;
+};
+
+/**
+ * struct n_hdlc - per device instance data structure
+ * @magic - magic value for structure
+ * @flags - miscellaneous control flags
+ * @tty - ptr to TTY structure
+ * @backup_tty - TTY to use if tty gets closed
+ * @tbusy - reentrancy flag for tx wakeup code
+ * @woke_up - FIXME: describe this field
+ * @tbuf - currently transmitting tx buffer
+ * @tx_buf_list - list of pending transmit frame buffers
+ * @rx_buf_list - list of received frame buffers
+ * @tx_free_buf_list - list unused transmit frame buffers
+ * @rx_free_buf_list - list unused received frame buffers
+ */
+struct n_hdlc {
+       int                     magic;
+       __u32                   flags;
+       struct tty_struct       *tty;
+       struct tty_struct       *backup_tty;
+       int                     tbusy;
+       int                     woke_up;
+       struct n_hdlc_buf       *tbuf;
+       struct n_hdlc_buf_list  tx_buf_list;
+       struct n_hdlc_buf_list  rx_buf_list;
+       struct n_hdlc_buf_list  tx_free_buf_list;
+       struct n_hdlc_buf_list  rx_free_buf_list;
+};
+
+/*
+ * HDLC buffer list manipulation functions
+ */
+static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list);
+static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
+                          struct n_hdlc_buf *buf);
+static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
+
+/* Local functions */
+
+static struct n_hdlc *n_hdlc_alloc (void);
+
+/* debug level can be set by insmod for debugging purposes */
+#define DEBUG_LEVEL_INFO       1
+static int debuglevel;
+
+/* max frame size for memory allocations */
+static int maxframe = 4096;
+
+/* TTY callbacks */
+
+static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
+                          __u8 __user *buf, size_t nr);
+static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
+                           const unsigned char *buf, size_t nr);
+static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
+                           unsigned int cmd, unsigned long arg);
+static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
+                                   poll_table *wait);
+static int n_hdlc_tty_open(struct tty_struct *tty);
+static void n_hdlc_tty_close(struct tty_struct *tty);
+static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp,
+                              char *fp, int count);
+static void n_hdlc_tty_wakeup(struct tty_struct *tty);
+
+#define bset(p,b)      ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
+
+#define tty2n_hdlc(tty)        ((struct n_hdlc *) ((tty)->disc_data))
+#define n_hdlc2tty(n_hdlc)     ((n_hdlc)->tty)
+
+static void flush_rx_queue(struct tty_struct *tty)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+       struct n_hdlc_buf *buf;
+
+       while ((buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list)))
+               n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, buf);
+}
+
+static void flush_tx_queue(struct tty_struct *tty)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+       struct n_hdlc_buf *buf;
+       unsigned long flags;
+
+       while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
+               n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
+       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
+       if (n_hdlc->tbuf) {
+               n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf);
+               n_hdlc->tbuf = NULL;
+       }
+       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
+}
+
+static struct tty_ldisc_ops n_hdlc_ldisc = {
+       .owner          = THIS_MODULE,
+       .magic          = TTY_LDISC_MAGIC,
+       .name           = "hdlc",
+       .open           = n_hdlc_tty_open,
+       .close          = n_hdlc_tty_close,
+       .read           = n_hdlc_tty_read,
+       .write          = n_hdlc_tty_write,
+       .ioctl          = n_hdlc_tty_ioctl,
+       .poll           = n_hdlc_tty_poll,
+       .receive_buf    = n_hdlc_tty_receive,
+       .write_wakeup   = n_hdlc_tty_wakeup,
+       .flush_buffer   = flush_rx_queue,
+};
+
+/**
+ * n_hdlc_release - release an n_hdlc per device line discipline info structure
+ * @n_hdlc - per device line discipline info structure
+ */
+static void n_hdlc_release(struct n_hdlc *n_hdlc)
+{
+       struct tty_struct *tty = n_hdlc2tty (n_hdlc);
+       struct n_hdlc_buf *buf;
+       
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__);
+               
+       /* Ensure that the n_hdlcd process is not hanging on select()/poll() */
+       wake_up_interruptible (&tty->read_wait);
+       wake_up_interruptible (&tty->write_wait);
+
+       if (tty->disc_data == n_hdlc)
+               tty->disc_data = NULL;  /* Break the tty->n_hdlc link */
+
+       /* Release transmit and receive buffers */
+       for(;;) {
+               buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
+               if (buf) {
+                       kfree(buf);
+               } else
+                       break;
+       }
+       for(;;) {
+               buf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
+               if (buf) {
+                       kfree(buf);
+               } else
+                       break;
+       }
+       for(;;) {
+               buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
+               if (buf) {
+                       kfree(buf);
+               } else
+                       break;
+       }
+       for(;;) {
+               buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
+               if (buf) {
+                       kfree(buf);
+               } else
+                       break;
+       }
+       kfree(n_hdlc->tbuf);
+       kfree(n_hdlc);
+       
+}      /* end of n_hdlc_release() */
+
+/**
+ * n_hdlc_tty_close - line discipline close
+ * @tty - pointer to tty info structure
+ *
+ * Called when the line discipline is changed to something
+ * else, the tty is closed, or the tty detects a hangup.
+ */
+static void n_hdlc_tty_close(struct tty_struct *tty)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_close() called\n",__FILE__,__LINE__);
+               
+       if (n_hdlc != NULL) {
+               if (n_hdlc->magic != HDLC_MAGIC) {
+                       printk (KERN_WARNING"n_hdlc: trying to close unopened tty!\n");
+                       return;
+               }
+#if defined(TTY_NO_WRITE_SPLIT)
+               clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
+#endif
+               tty->disc_data = NULL;
+               if (tty == n_hdlc->backup_tty)
+                       n_hdlc->backup_tty = NULL;
+               if (tty != n_hdlc->tty)
+                       return;
+               if (n_hdlc->backup_tty) {
+                       n_hdlc->tty = n_hdlc->backup_tty;
+               } else {
+                       n_hdlc_release (n_hdlc);
+               }
+       }
+       
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_close() success\n",__FILE__,__LINE__);
+               
+}      /* end of n_hdlc_tty_close() */
+
+/**
+ * n_hdlc_tty_open - called when line discipline changed to n_hdlc
+ * @tty - pointer to tty info structure
+ *
+ * Returns 0 if success, otherwise error code
+ */
+static int n_hdlc_tty_open (struct tty_struct *tty)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_open() called (device=%s)\n",
+               __FILE__,__LINE__,
+               tty->name);
+               
+       /* There should not be an existing table for this slot. */
+       if (n_hdlc) {
+               printk (KERN_ERR"n_hdlc_tty_open:tty already associated!\n" );
+               return -EEXIST;
+       }
+       
+       n_hdlc = n_hdlc_alloc();
+       if (!n_hdlc) {
+               printk (KERN_ERR "n_hdlc_alloc failed\n");
+               return -ENFILE;
+       }
+               
+       tty->disc_data = n_hdlc;
+       n_hdlc->tty    = tty;
+       tty->receive_room = 65536;
+       
+#if defined(TTY_NO_WRITE_SPLIT)
+       /* change tty_io write() to not split large writes into 8K chunks */
+       set_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
+#endif
+       
+       /* flush receive data from driver */
+       tty_driver_flush_buffer(tty);
+               
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__);
+               
+       return 0;
+       
+}      /* end of n_tty_hdlc_open() */
+
+/**
+ * n_hdlc_send_frames - send frames on pending send buffer list
+ * @n_hdlc - pointer to ldisc instance data
+ * @tty - pointer to tty instance data
+ *
+ * Send frames on pending send buffer list until the driver does not accept a
+ * frame (busy) this function is called after adding a frame to the send buffer
+ * list and by the tty wakeup callback.
+ */
+static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
+{
+       register int actual;
+       unsigned long flags;
+       struct n_hdlc_buf *tbuf;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__);
+ check_again:
+               
+       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
+       if (n_hdlc->tbusy) {
+               n_hdlc->woke_up = 1;
+               spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
+               return;
+       }
+       n_hdlc->tbusy = 1;
+       n_hdlc->woke_up = 0;
+       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
+
+       /* get current transmit buffer or get new transmit */
+       /* buffer from list of pending transmit buffers */
+               
+       tbuf = n_hdlc->tbuf;
+       if (!tbuf)
+               tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
+               
+       while (tbuf) {
+               if (debuglevel >= DEBUG_LEVEL_INFO)     
+                       printk("%s(%d)sending frame %p, count=%d\n",
+                               __FILE__,__LINE__,tbuf,tbuf->count);
+                       
+               /* Send the next block of data to device */
+               tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+               actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
+
+               /* rollback was possible and has been done */
+               if (actual == -ERESTARTSYS) {
+                       n_hdlc->tbuf = tbuf;
+                       break;
+               }
+               /* if transmit error, throw frame away by */
+               /* pretending it was accepted by driver */
+               if (actual < 0)
+                       actual = tbuf->count;
+               
+               if (actual == tbuf->count) {
+                       if (debuglevel >= DEBUG_LEVEL_INFO)     
+                               printk("%s(%d)frame %p completed\n",
+                                       __FILE__,__LINE__,tbuf);
+                                       
+                       /* free current transmit buffer */
+                       n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf);
+                       
+                       /* this tx buffer is done */
+                       n_hdlc->tbuf = NULL;
+                       
+                       /* wait up sleeping writers */
+                       wake_up_interruptible(&tty->write_wait);
+       
+                       /* get next pending transmit buffer */
+                       tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
+               } else {
+                       if (debuglevel >= DEBUG_LEVEL_INFO)     
+                               printk("%s(%d)frame %p pending\n",
+                                       __FILE__,__LINE__,tbuf);
+                                       
+                       /* buffer not accepted by driver */
+                       /* set this buffer as pending buffer */
+                       n_hdlc->tbuf = tbuf;
+                       break;
+               }
+       }
+       
+       if (!tbuf)
+               tty->flags  &= ~(1 << TTY_DO_WRITE_WAKEUP);
+       
+       /* Clear the re-entry flag */
+       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
+       n_hdlc->tbusy = 0;
+       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); 
+       
+        if (n_hdlc->woke_up)
+         goto check_again;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_send_frames() exit\n",__FILE__,__LINE__);
+               
+}      /* end of n_hdlc_send_frames() */
+
+/**
+ * n_hdlc_tty_wakeup - Callback for transmit wakeup
+ * @tty        - pointer to associated tty instance data
+ *
+ * Called when low level device driver can accept more send data.
+ */
+static void n_hdlc_tty_wakeup(struct tty_struct *tty)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_wakeup() called\n",__FILE__,__LINE__);
+               
+       if (!n_hdlc)
+               return;
+
+       if (tty != n_hdlc->tty) {
+               tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+               return;
+       }
+
+       n_hdlc_send_frames (n_hdlc, tty);
+               
+}      /* end of n_hdlc_tty_wakeup() */
+
+/**
+ * n_hdlc_tty_receive - Called by tty driver when receive data is available
+ * @tty        - pointer to tty instance data
+ * @data - pointer to received data
+ * @flags - pointer to flags for data
+ * @count - count of received data in bytes
+ *
+ * Called by tty low level driver when receive data is available. Data is
+ * interpreted as one HDLC frame.
+ */
+static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
+                              char *flags, int count)
+{
+       register struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+       register struct n_hdlc_buf *buf;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_receive() called count=%d\n",
+                       __FILE__,__LINE__, count);
+               
+       /* This can happen if stuff comes in on the backup tty */
+       if (!n_hdlc || tty != n_hdlc->tty)
+               return;
+               
+       /* verify line is using HDLC discipline */
+       if (n_hdlc->magic != HDLC_MAGIC) {
+               printk("%s(%d) line not using HDLC discipline\n",
+                       __FILE__,__LINE__);
+               return;
+       }
+       
+       if ( count>maxframe ) {
+               if (debuglevel >= DEBUG_LEVEL_INFO)     
+                       printk("%s(%d) rx count>maxframesize, data discarded\n",
+                              __FILE__,__LINE__);
+               return;
+       }
+
+       /* get a free HDLC buffer */    
+       buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
+       if (!buf) {
+               /* no buffers in free list, attempt to allocate another rx buffer */
+               /* unless the maximum count has been reached */
+               if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT)
+                       buf = kmalloc(N_HDLC_BUF_SIZE, GFP_ATOMIC);
+       }
+       
+       if (!buf) {
+               if (debuglevel >= DEBUG_LEVEL_INFO)     
+                       printk("%s(%d) no more rx buffers, data discarded\n",
+                              __FILE__,__LINE__);
+               return;
+       }
+               
+       /* copy received data to HDLC buffer */
+       memcpy(buf->buf,data,count);
+       buf->count=count;
+
+       /* add HDLC buffer to list of received frames */
+       n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf);
+       
+       /* wake up any blocked reads and perform async signalling */
+       wake_up_interruptible (&tty->read_wait);
+       if (n_hdlc->tty->fasync != NULL)
+               kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN);
+
+}      /* end of n_hdlc_tty_receive() */
+
+/**
+ * n_hdlc_tty_read - Called to retrieve one frame of data (if available)
+ * @tty - pointer to tty instance data
+ * @file - pointer to open file object
+ * @buf - pointer to returned data buffer
+ * @nr - size of returned data buffer
+ *     
+ * Returns the number of bytes returned or error code.
+ */
+static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
+                          __u8 __user *buf, size_t nr)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+       int ret;
+       struct n_hdlc_buf *rbuf;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__);
+               
+       /* Validate the pointers */
+       if (!n_hdlc)
+               return -EIO;
+
+       /* verify user access to buffer */
+       if (!access_ok(VERIFY_WRITE, buf, nr)) {
+               printk(KERN_WARNING "%s(%d) n_hdlc_tty_read() can't verify user "
+               "buffer\n", __FILE__, __LINE__);
+               return -EFAULT;
+       }
+
+       tty_lock();
+
+       for (;;) {
+               if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
+                       tty_unlock();
+                       return -EIO;
+               }
+
+               n_hdlc = tty2n_hdlc (tty);
+               if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||
+                        tty != n_hdlc->tty) {
+                       tty_unlock();
+                       return 0;
+               }
+
+               rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
+               if (rbuf)
+                       break;
+                       
+               /* no data */
+               if (file->f_flags & O_NONBLOCK) {
+                       tty_unlock();
+                       return -EAGAIN;
+               }
+                       
+               interruptible_sleep_on (&tty->read_wait);
+               if (signal_pending(current)) {
+                       tty_unlock();
+                       return -EINTR;
+               }
+       }
+               
+       if (rbuf->count > nr)
+               /* frame too large for caller's buffer (discard frame) */
+               ret = -EOVERFLOW;
+       else {
+               /* Copy the data to the caller's buffer */
+               if (copy_to_user(buf, rbuf->buf, rbuf->count))
+                       ret = -EFAULT;
+               else
+                       ret = rbuf->count;
+       }
+       
+       /* return HDLC buffer to free list unless the free list */
+       /* count has exceeded the default value, in which case the */
+       /* buffer is freed back to the OS to conserve memory */
+       if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT)
+               kfree(rbuf);
+       else    
+               n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf);
+       tty_unlock();
+       return ret;
+       
+}      /* end of n_hdlc_tty_read() */
+
+/**
+ * n_hdlc_tty_write - write a single frame of data to device
+ * @tty        - pointer to associated tty device instance data
+ * @file - pointer to file object data
+ * @data - pointer to transmit data (one frame)
+ * @count - size of transmit frame in bytes
+ *             
+ * Returns the number of bytes written (or error code).
+ */
+static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
+                           const unsigned char *data, size_t count)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+       int error = 0;
+       DECLARE_WAITQUEUE(wait, current);
+       struct n_hdlc_buf *tbuf;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_write() called count=%Zd\n",
+                       __FILE__,__LINE__,count);
+               
+       /* Verify pointers */
+       if (!n_hdlc)
+               return -EIO;
+
+       if (n_hdlc->magic != HDLC_MAGIC)
+               return -EIO;
+
+       /* verify frame size */
+       if (count > maxframe ) {
+               if (debuglevel & DEBUG_LEVEL_INFO)
+                       printk (KERN_WARNING
+                               "n_hdlc_tty_write: truncating user packet "
+                               "from %lu to %d\n", (unsigned long) count,
+                               maxframe );
+               count = maxframe;
+       }
+       
+       tty_lock();
+
+       add_wait_queue(&tty->write_wait, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+       
+       /* Allocate transmit buffer */
+       /* sleep until transmit buffer available */             
+       while (!(tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list))) {
+               if (file->f_flags & O_NONBLOCK) {
+                       error = -EAGAIN;
+                       break;
+               }
+               schedule();
+                       
+               n_hdlc = tty2n_hdlc (tty);
+               if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || 
+                   tty != n_hdlc->tty) {
+                       printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc);
+                       error = -EIO;
+                       break;
+               }
+                       
+               if (signal_pending(current)) {
+                       error = -EINTR;
+                       break;
+               }
+       }
+
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&tty->write_wait, &wait);
+
+       if (!error) {           
+               /* Retrieve the user's buffer */
+               memcpy(tbuf->buf, data, count);
+
+               /* Send the data */
+               tbuf->count = error = count;
+               n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf);
+               n_hdlc_send_frames(n_hdlc,tty);
+       }
+       tty_unlock();
+       return error;
+       
+}      /* end of n_hdlc_tty_write() */
+
+/**
+ * n_hdlc_tty_ioctl - process IOCTL system call for the tty device.
+ * @tty - pointer to tty instance data
+ * @file - pointer to open file object for device
+ * @cmd - IOCTL command code
+ * @arg - argument for IOCTL call (cmd dependent)
+ *
+ * Returns command dependent result.
+ */
+static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
+                           unsigned int cmd, unsigned long arg)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+       int error = 0;
+       int count;
+       unsigned long flags;
+       
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
+                       __FILE__,__LINE__,cmd);
+               
+       /* Verify the status of the device */
+       if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC)
+               return -EBADF;
+
+       switch (cmd) {
+       case FIONREAD:
+               /* report count of read data available */
+               /* in next available frame (if any) */
+               spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
+               if (n_hdlc->rx_buf_list.head)
+                       count = n_hdlc->rx_buf_list.head->count;
+               else
+                       count = 0;
+               spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
+               error = put_user(count, (int __user *)arg);
+               break;
+
+       case TIOCOUTQ:
+               /* get the pending tx byte count in the driver */
+               count = tty_chars_in_buffer(tty);
+               /* add size of next output frame in queue */
+               spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
+               if (n_hdlc->tx_buf_list.head)
+                       count += n_hdlc->tx_buf_list.head->count;
+               spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
+               error = put_user(count, (int __user *)arg);
+               break;
+
+       case TCFLSH:
+               switch (arg) {
+               case TCIOFLUSH:
+               case TCOFLUSH:
+                       flush_tx_queue(tty);
+               }
+               /* fall through to default */
+
+       default:
+               error = n_tty_ioctl_helper(tty, file, cmd, arg);
+               break;
+       }
+       return error;
+       
+}      /* end of n_hdlc_tty_ioctl() */
+
+/**
+ * n_hdlc_tty_poll - TTY callback for poll system call
+ * @tty - pointer to tty instance data
+ * @filp - pointer to open file object for device
+ * @poll_table - wait queue for operations
+ * 
+ * Determine which operations (read/write) will not block and return info
+ * to caller.
+ * Returns a bit mask containing info on which ops will not block.
+ */
+static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
+                                   poll_table *wait)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+       unsigned int mask = 0;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_poll() called\n",__FILE__,__LINE__);
+               
+       if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) {
+               /* queue current process into any wait queue that */
+               /* may awaken in the future (read and write) */
+
+               poll_wait(filp, &tty->read_wait, wait);
+               poll_wait(filp, &tty->write_wait, wait);
+
+               /* set bits for operations that won't block */
+               if (n_hdlc->rx_buf_list.head)
+                       mask |= POLLIN | POLLRDNORM;    /* readable */
+               if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+                       mask |= POLLHUP;
+               if (tty_hung_up_p(filp))
+                       mask |= POLLHUP;
+               if (!tty_is_writelocked(tty) &&
+                               n_hdlc->tx_free_buf_list.head)
+                       mask |= POLLOUT | POLLWRNORM;   /* writable */
+       }
+       return mask;
+}      /* end of n_hdlc_tty_poll() */
+
+/**
+ * n_hdlc_alloc - allocate an n_hdlc instance data structure
+ *
+ * Returns a pointer to newly created structure if success, otherwise %NULL
+ */
+static struct n_hdlc *n_hdlc_alloc(void)
+{
+       struct n_hdlc_buf *buf;
+       int i;
+       struct n_hdlc *n_hdlc = kmalloc(sizeof(*n_hdlc), GFP_KERNEL);
+
+       if (!n_hdlc)
+               return NULL;
+
+       memset(n_hdlc, 0, sizeof(*n_hdlc));
+
+       n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);
+       n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);
+       n_hdlc_buf_list_init(&n_hdlc->rx_buf_list);
+       n_hdlc_buf_list_init(&n_hdlc->tx_buf_list);
+       
+       /* allocate free rx buffer list */
+       for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
+               buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
+               if (buf)
+                       n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,buf);
+               else if (debuglevel >= DEBUG_LEVEL_INFO)        
+                       printk("%s(%d)n_hdlc_alloc(), kalloc() failed for rx buffer %d\n",__FILE__,__LINE__, i);
+       }
+       
+       /* allocate free tx buffer list */
+       for(i=0;i<DEFAULT_TX_BUF_COUNT;i++) {
+               buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
+               if (buf)
+                       n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,buf);
+               else if (debuglevel >= DEBUG_LEVEL_INFO)        
+                       printk("%s(%d)n_hdlc_alloc(), kalloc() failed for tx buffer %d\n",__FILE__,__LINE__, i);
+       }
+       
+       /* Initialize the control block */
+       n_hdlc->magic  = HDLC_MAGIC;
+       n_hdlc->flags  = 0;
+       
+       return n_hdlc;
+       
+}      /* end of n_hdlc_alloc() */
+
+/**
+ * n_hdlc_buf_list_init - initialize specified HDLC buffer list
+ * @list - pointer to buffer list
+ */
+static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list)
+{
+       memset(list, 0, sizeof(*list));
+       spin_lock_init(&list->spinlock);
+}      /* end of n_hdlc_buf_list_init() */
+
+/**
+ * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
+ * @list - pointer to buffer list
+ * @buf        - pointer to buffer
+ */
+static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
+                          struct n_hdlc_buf *buf)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&list->spinlock,flags);
+       
+       buf->link=NULL;
+       if (list->tail)
+               list->tail->link = buf;
+       else
+               list->head = buf;
+       list->tail = buf;
+       (list->count)++;
+       
+       spin_unlock_irqrestore(&list->spinlock,flags);
+       
+}      /* end of n_hdlc_buf_put() */
+
+/**
+ * n_hdlc_buf_get - remove and return an HDLC buffer from list
+ * @list - pointer to HDLC buffer list
+ * 
+ * Remove and return an HDLC buffer from the head of the specified HDLC buffer
+ * list.
+ * Returns a pointer to HDLC buffer if available, otherwise %NULL.
+ */
+static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list)
+{
+       unsigned long flags;
+       struct n_hdlc_buf *buf;
+       spin_lock_irqsave(&list->spinlock,flags);
+       
+       buf = list->head;
+       if (buf) {
+               list->head = buf->link;
+               (list->count)--;
+       }
+       if (!list->head)
+               list->tail = NULL;
+       
+       spin_unlock_irqrestore(&list->spinlock,flags);
+       return buf;
+       
+}      /* end of n_hdlc_buf_get() */
+
+static char hdlc_banner[] __initdata =
+       KERN_INFO "HDLC line discipline maxframe=%u\n";
+static char hdlc_register_ok[] __initdata =
+       KERN_INFO "N_HDLC line discipline registered.\n";
+static char hdlc_register_fail[] __initdata =
+       KERN_ERR "error registering line discipline: %d\n";
+static char hdlc_init_fail[] __initdata =
+       KERN_INFO "N_HDLC: init failure %d\n";
+
+static int __init n_hdlc_init(void)
+{
+       int status;
+
+       /* range check maxframe arg */
+       if (maxframe < 4096)
+               maxframe = 4096;
+       else if (maxframe > 65535)
+               maxframe = 65535;
+
+       printk(hdlc_banner, maxframe);
+
+       status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc);
+       if (!status)
+               printk(hdlc_register_ok);
+       else
+               printk(hdlc_register_fail, status);
+
+       if (status)
+               printk(hdlc_init_fail, status);
+       return status;
+       
+}      /* end of init_module() */
+
+static char hdlc_unregister_ok[] __exitdata =
+       KERN_INFO "N_HDLC: line discipline unregistered\n";
+static char hdlc_unregister_fail[] __exitdata =
+       KERN_ERR "N_HDLC: can't unregister line discipline (err = %d)\n";
+
+static void __exit n_hdlc_exit(void)
+{
+       /* Release tty registration of line discipline */
+       int status = tty_unregister_ldisc(N_HDLC);
+
+       if (status)
+               printk(hdlc_unregister_fail, status);
+       else
+               printk(hdlc_unregister_ok);
+}
+
+module_init(n_hdlc_init);
+module_exit(n_hdlc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com");
+module_param(debuglevel, int, 0);
+module_param(maxframe, int, 0);
+MODULE_ALIAS_LDISC(N_HDLC);
diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c
new file mode 100644 (file)
index 0000000..88dda0c
--- /dev/null
@@ -0,0 +1,1264 @@
+/* r3964 linediscipline for linux
+ *
+ * -----------------------------------------------------------
+ * Copyright by 
+ * Philips Automation Projects
+ * Kassel (Germany)
+ * -----------------------------------------------------------
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ *
+ * Author:
+ * L. Haag
+ *
+ * $Log: n_r3964.c,v $
+ * Revision 1.10  2001/03/18 13:02:24  dwmw2
+ * Fix timer usage, use spinlocks properly.
+ *
+ * Revision 1.9  2001/03/18 12:52:14  dwmw2
+ * Merge changes in 2.4.2
+ *
+ * Revision 1.8  2000/03/23 14:14:54  dwmw2
+ * Fix race in sleeping in r3964_read()
+ *
+ * Revision 1.7  1999/28/08 11:41:50  dwmw2
+ * Port to 2.3 kernel
+ *
+ * Revision 1.6  1998/09/30 00:40:40  dwmw2
+ * Fixed compilation on 2.0.x kernels
+ * Updated to newly registered tty-ldisc number 9
+ *
+ * Revision 1.5  1998/09/04 21:57:36  dwmw2
+ * Signal handling bug fixes, port to 2.1.x.
+ *
+ * Revision 1.4  1998/04/02 20:26:59  lhaag
+ * select, blocking, ...
+ *
+ * Revision 1.3  1998/02/12 18:58:43  root
+ * fixed some memory leaks
+ * calculation of checksum characters
+ *
+ * Revision 1.2  1998/02/07 13:03:34  root
+ * ioctl read_telegram
+ *
+ * Revision 1.1  1998/02/06 19:21:03  root
+ * Initial revision
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h>      /* used in new tty drivers */
+#include <linux/signal.h>      /* used in new tty drivers */
+#include <linux/ioctl.h>
+#include <linux/n_r3964.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+/*#define DEBUG_QUEUE*/
+
+/* Log successful handshake and protocol operations  */
+/*#define DEBUG_PROTO_S*/
+
+/* Log handshake and protocol errors: */
+/*#define DEBUG_PROTO_E*/
+
+/* Log Linediscipline operations (open, close, read, write...): */
+/*#define DEBUG_LDISC*/
+
+/* Log module and memory operations (init, cleanup; kmalloc, kfree): */
+/*#define DEBUG_MODUL*/
+
+/* Macro helpers for debug output: */
+#define TRACE(format, args...) printk("r3964: " format "\n" , ## args)
+
+#ifdef DEBUG_MODUL
+#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args)
+#else
+#define TRACE_M(fmt, arg...) do {} while (0)
+#endif
+#ifdef DEBUG_PROTO_S
+#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args)
+#else
+#define TRACE_PS(fmt, arg...) do {} while (0)
+#endif
+#ifdef DEBUG_PROTO_E
+#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args)
+#else
+#define TRACE_PE(fmt, arg...) do {} while (0)
+#endif
+#ifdef DEBUG_LDISC
+#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args)
+#else
+#define TRACE_L(fmt, arg...) do {} while (0)
+#endif
+#ifdef DEBUG_QUEUE
+#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args)
+#else
+#define TRACE_Q(fmt, arg...) do {} while (0)
+#endif
+static void add_tx_queue(struct r3964_info *, struct r3964_block_header *);
+static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code);
+static void put_char(struct r3964_info *pInfo, unsigned char ch);
+static void trigger_transmit(struct r3964_info *pInfo);
+static void retry_transmit(struct r3964_info *pInfo);
+static void transmit_block(struct r3964_info *pInfo);
+static void receive_char(struct r3964_info *pInfo, const unsigned char c);
+static void receive_error(struct r3964_info *pInfo, const char flag);
+static void on_timeout(unsigned long priv);
+static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg);
+static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
+               unsigned char __user * buf);
+static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
+               int error_code, struct r3964_block_header *pBlock);
+static struct r3964_message *remove_msg(struct r3964_info *pInfo,
+               struct r3964_client_info *pClient);
+static void remove_client_block(struct r3964_info *pInfo,
+               struct r3964_client_info *pClient);
+
+static int r3964_open(struct tty_struct *tty);
+static void r3964_close(struct tty_struct *tty);
+static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
+               unsigned char __user * buf, size_t nr);
+static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
+               const unsigned char *buf, size_t nr);
+static int r3964_ioctl(struct tty_struct *tty, struct file *file,
+               unsigned int cmd, unsigned long arg);
+static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);
+static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
+               struct poll_table_struct *wait);
+static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+               char *fp, int count);
+
+static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
+       .owner = THIS_MODULE,
+       .magic = TTY_LDISC_MAGIC,
+       .name = "R3964",
+       .open = r3964_open,
+       .close = r3964_close,
+       .read = r3964_read,
+       .write = r3964_write,
+       .ioctl = r3964_ioctl,
+       .set_termios = r3964_set_termios,
+       .poll = r3964_poll,
+       .receive_buf = r3964_receive_buf,
+};
+
+static void dump_block(const unsigned char *block, unsigned int length)
+{
+       unsigned int i, j;
+       char linebuf[16 * 3 + 1];
+
+       for (i = 0; i < length; i += 16) {
+               for (j = 0; (j < 16) && (j + i < length); j++) {
+                       sprintf(linebuf + 3 * j, "%02x ", block[i + j]);
+               }
+               linebuf[3 * j] = '\0';
+               TRACE_PS("%s", linebuf);
+       }
+}
+
+/*************************************************************
+ * Driver initialisation
+ *************************************************************/
+
+/*************************************************************
+ * Module support routines
+ *************************************************************/
+
+static void __exit r3964_exit(void)
+{
+       int status;
+
+       TRACE_M("cleanup_module()");
+
+       status = tty_unregister_ldisc(N_R3964);
+
+       if (status != 0) {
+               printk(KERN_ERR "r3964: error unregistering linediscipline: "
+                               "%d\n", status);
+       } else {
+               TRACE_L("linediscipline successfully unregistered");
+       }
+}
+
+static int __init r3964_init(void)
+{
+       int status;
+
+       printk("r3964: Philips r3964 Driver $Revision: 1.10 $\n");
+
+       /*
+        * Register the tty line discipline
+        */
+
+       status = tty_register_ldisc(N_R3964, &tty_ldisc_N_R3964);
+       if (status == 0) {
+               TRACE_L("line discipline %d registered", N_R3964);
+               TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags,
+                       tty_ldisc_N_R3964.num);
+               TRACE_L("open=%p", tty_ldisc_N_R3964.open);
+               TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964);
+       } else {
+               printk(KERN_ERR "r3964: error registering line discipline: "
+                               "%d\n", status);
+       }
+       return status;
+}
+
+module_init(r3964_init);
+module_exit(r3964_exit);
+
+/*************************************************************
+ * Protocol implementation routines
+ *************************************************************/
+
+static void add_tx_queue(struct r3964_info *pInfo,
+                        struct r3964_block_header *pHeader)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pInfo->lock, flags);
+
+       pHeader->next = NULL;
+
+       if (pInfo->tx_last == NULL) {
+               pInfo->tx_first = pInfo->tx_last = pHeader;
+       } else {
+               pInfo->tx_last->next = pHeader;
+               pInfo->tx_last = pHeader;
+       }
+
+       spin_unlock_irqrestore(&pInfo->lock, flags);
+
+       TRACE_Q("add_tx_queue %p, length %d, tx_first = %p",
+               pHeader, pHeader->length, pInfo->tx_first);
+}
+
+static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code)
+{
+       struct r3964_block_header *pHeader;
+       unsigned long flags;
+#ifdef DEBUG_QUEUE
+       struct r3964_block_header *pDump;
+#endif
+
+       pHeader = pInfo->tx_first;
+
+       if (pHeader == NULL)
+               return;
+
+#ifdef DEBUG_QUEUE
+       printk("r3964: remove_from_tx_queue: %p, length %u - ",
+               pHeader, pHeader->length);
+       for (pDump = pHeader; pDump; pDump = pDump->next)
+               printk("%p ", pDump);
+       printk("\n");
+#endif
+
+       if (pHeader->owner) {
+               if (error_code) {
+                       add_msg(pHeader->owner, R3964_MSG_ACK, 0,
+                               error_code, NULL);
+               } else {
+                       add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,
+                               error_code, NULL);
+               }
+               wake_up_interruptible(&pInfo->read_wait);
+       }
+
+       spin_lock_irqsave(&pInfo->lock, flags);
+
+       pInfo->tx_first = pHeader->next;
+       if (pInfo->tx_first == NULL) {
+               pInfo->tx_last = NULL;
+       }
+
+       spin_unlock_irqrestore(&pInfo->lock, flags);
+
+       kfree(pHeader);
+       TRACE_M("remove_from_tx_queue - kfree %p", pHeader);
+
+       TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p",
+               pInfo->tx_first, pInfo->tx_last);
+}
+
+static void add_rx_queue(struct r3964_info *pInfo,
+                        struct r3964_block_header *pHeader)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pInfo->lock, flags);
+
+       pHeader->next = NULL;
+
+       if (pInfo->rx_last == NULL) {
+               pInfo->rx_first = pInfo->rx_last = pHeader;
+       } else {
+               pInfo->rx_last->next = pHeader;
+               pInfo->rx_last = pHeader;
+       }
+       pInfo->blocks_in_rx_queue++;
+
+       spin_unlock_irqrestore(&pInfo->lock, flags);
+
+       TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d",
+               pHeader, pHeader->length,
+               pInfo->rx_first, pInfo->blocks_in_rx_queue);
+}
+
+static void remove_from_rx_queue(struct r3964_info *pInfo,
+                                struct r3964_block_header *pHeader)
+{
+       unsigned long flags;
+       struct r3964_block_header *pFind;
+
+       if (pHeader == NULL)
+               return;
+
+       TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
+               pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
+       TRACE_Q("remove_from_rx_queue: %p, length %u",
+               pHeader, pHeader->length);
+
+       spin_lock_irqsave(&pInfo->lock, flags);
+
+       if (pInfo->rx_first == pHeader) {
+               /* Remove the first block in the linked list: */
+               pInfo->rx_first = pHeader->next;
+
+               if (pInfo->rx_first == NULL) {
+                       pInfo->rx_last = NULL;
+               }
+               pInfo->blocks_in_rx_queue--;
+       } else {
+               /* Find block to remove: */
+               for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) {
+                       if (pFind->next == pHeader) {
+                               /* Got it. */
+                               pFind->next = pHeader->next;
+                               pInfo->blocks_in_rx_queue--;
+                               if (pFind->next == NULL) {
+                                       /* Oh, removed the last one! */
+                                       pInfo->rx_last = pFind;
+                               }
+                               break;
+                       }
+               }
+       }
+
+       spin_unlock_irqrestore(&pInfo->lock, flags);
+
+       kfree(pHeader);
+       TRACE_M("remove_from_rx_queue - kfree %p", pHeader);
+
+       TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
+               pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
+}
+
+static void put_char(struct r3964_info *pInfo, unsigned char ch)
+{
+       struct tty_struct *tty = pInfo->tty;
+       /* FIXME: put_char should not be called from an IRQ */
+       tty_put_char(tty, ch);
+       pInfo->bcc ^= ch;
+}
+
+static void flush(struct r3964_info *pInfo)
+{
+       struct tty_struct *tty = pInfo->tty;
+
+       if (tty == NULL || tty->ops->flush_chars == NULL)
+               return;
+       tty->ops->flush_chars(tty);
+}
+
+static void trigger_transmit(struct r3964_info *pInfo)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pInfo->lock, flags);
+
+       if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) {
+               pInfo->state = R3964_TX_REQUEST;
+               pInfo->nRetry = 0;
+               pInfo->flags &= ~R3964_ERROR;
+               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
+
+               spin_unlock_irqrestore(&pInfo->lock, flags);
+
+               TRACE_PS("trigger_transmit - sent STX");
+
+               put_char(pInfo, STX);
+               flush(pInfo);
+
+               pInfo->bcc = 0;
+       } else {
+               spin_unlock_irqrestore(&pInfo->lock, flags);
+       }
+}
+
+static void retry_transmit(struct r3964_info *pInfo)
+{
+       if (pInfo->nRetry < R3964_MAX_RETRIES) {
+               TRACE_PE("transmission failed. Retry #%d", pInfo->nRetry);
+               pInfo->bcc = 0;
+               put_char(pInfo, STX);
+               flush(pInfo);
+               pInfo->state = R3964_TX_REQUEST;
+               pInfo->nRetry++;
+               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
+       } else {
+               TRACE_PE("transmission failed after %d retries",
+                        R3964_MAX_RETRIES);
+
+               remove_from_tx_queue(pInfo, R3964_TX_FAIL);
+
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               pInfo->state = R3964_IDLE;
+
+               trigger_transmit(pInfo);
+       }
+}
+
+static void transmit_block(struct r3964_info *pInfo)
+{
+       struct tty_struct *tty = pInfo->tty;
+       struct r3964_block_header *pBlock = pInfo->tx_first;
+       int room = 0;
+
+       if (tty == NULL || pBlock == NULL) {
+               return;
+       }
+
+       room = tty_write_room(tty);
+
+       TRACE_PS("transmit_block %p, room %d, length %d",
+                pBlock, room, pBlock->length);
+
+       while (pInfo->tx_position < pBlock->length) {
+               if (room < 2)
+                       break;
+
+               if (pBlock->data[pInfo->tx_position] == DLE) {
+                       /* send additional DLE char: */
+                       put_char(pInfo, DLE);
+               }
+               put_char(pInfo, pBlock->data[pInfo->tx_position++]);
+
+               room--;
+       }
+
+       if ((pInfo->tx_position == pBlock->length) && (room >= 3)) {
+               put_char(pInfo, DLE);
+               put_char(pInfo, ETX);
+               if (pInfo->flags & R3964_BCC) {
+                       put_char(pInfo, pInfo->bcc);
+               }
+               pInfo->state = R3964_WAIT_FOR_TX_ACK;
+               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
+       }
+       flush(pInfo);
+}
+
+static void on_receive_block(struct r3964_info *pInfo)
+{
+       unsigned int length;
+       struct r3964_client_info *pClient;
+       struct r3964_block_header *pBlock;
+
+       length = pInfo->rx_position;
+
+       /* compare byte checksum characters: */
+       if (pInfo->flags & R3964_BCC) {
+               if (pInfo->bcc != pInfo->last_rx) {
+                       TRACE_PE("checksum error - got %x but expected %x",
+                                pInfo->last_rx, pInfo->bcc);
+                       pInfo->flags |= R3964_CHECKSUM;
+               }
+       }
+
+       /* check for errors (parity, overrun,...): */
+       if (pInfo->flags & R3964_ERROR) {
+               TRACE_PE("on_receive_block - transmission failed error %x",
+                        pInfo->flags & R3964_ERROR);
+
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               if (pInfo->nRetry < R3964_MAX_RETRIES) {
+                       pInfo->state = R3964_WAIT_FOR_RX_REPEAT;
+                       pInfo->nRetry++;
+                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC);
+               } else {
+                       TRACE_PE("on_receive_block - failed after max retries");
+                       pInfo->state = R3964_IDLE;
+               }
+               return;
+       }
+
+       /* received block; submit DLE: */
+       put_char(pInfo, DLE);
+       flush(pInfo);
+       del_timer_sync(&pInfo->tmr);
+       TRACE_PS(" rx success: got %d chars", length);
+
+       /* prepare struct r3964_block_header: */
+       pBlock = kmalloc(length + sizeof(struct r3964_block_header),
+                       GFP_KERNEL);
+       TRACE_M("on_receive_block - kmalloc %p", pBlock);
+
+       if (pBlock == NULL)
+               return;
+
+       pBlock->length = length;
+       pBlock->data = ((unsigned char *)pBlock) +
+                       sizeof(struct r3964_block_header);
+       pBlock->locks = 0;
+       pBlock->next = NULL;
+       pBlock->owner = NULL;
+
+       memcpy(pBlock->data, pInfo->rx_buf, length);
+
+       /* queue block into rx_queue: */
+       add_rx_queue(pInfo, pBlock);
+
+       /* notify attached client processes: */
+       for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
+               if (pClient->sig_flags & R3964_SIG_DATA) {
+                       add_msg(pClient, R3964_MSG_DATA, length, R3964_OK,
+                               pBlock);
+               }
+       }
+       wake_up_interruptible(&pInfo->read_wait);
+
+       pInfo->state = R3964_IDLE;
+
+       trigger_transmit(pInfo);
+}
+
+static void receive_char(struct r3964_info *pInfo, const unsigned char c)
+{
+       switch (pInfo->state) {
+       case R3964_TX_REQUEST:
+               if (c == DLE) {
+                       TRACE_PS("TX_REQUEST - got DLE");
+
+                       pInfo->state = R3964_TRANSMITTING;
+                       pInfo->tx_position = 0;
+
+                       transmit_block(pInfo);
+               } else if (c == STX) {
+                       if (pInfo->nRetry == 0) {
+                               TRACE_PE("TX_REQUEST - init conflict");
+                               if (pInfo->priority == R3964_SLAVE) {
+                                       goto start_receiving;
+                               }
+                       } else {
+                               TRACE_PE("TX_REQUEST - secondary init "
+                                       "conflict!? Switching to SLAVE mode "
+                                       "for next rx.");
+                               goto start_receiving;
+                       }
+               } else {
+                       TRACE_PE("TX_REQUEST - char != DLE: %x", c);
+                       retry_transmit(pInfo);
+               }
+               break;
+       case R3964_TRANSMITTING:
+               if (c == NAK) {
+                       TRACE_PE("TRANSMITTING - got NAK");
+                       retry_transmit(pInfo);
+               } else {
+                       TRACE_PE("TRANSMITTING - got invalid char");
+
+                       pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY;
+                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
+               }
+               break;
+       case R3964_WAIT_FOR_TX_ACK:
+               if (c == DLE) {
+                       TRACE_PS("WAIT_FOR_TX_ACK - got DLE");
+                       remove_from_tx_queue(pInfo, R3964_OK);
+
+                       pInfo->state = R3964_IDLE;
+                       trigger_transmit(pInfo);
+               } else {
+                       retry_transmit(pInfo);
+               }
+               break;
+       case R3964_WAIT_FOR_RX_REPEAT:
+               /* FALLTHROUGH */
+       case R3964_IDLE:
+               if (c == STX) {
+                       /* Prevent rx_queue from overflow: */
+                       if (pInfo->blocks_in_rx_queue >=
+                           R3964_MAX_BLOCKS_IN_RX_QUEUE) {
+                               TRACE_PE("IDLE - got STX but no space in "
+                                               "rx_queue!");
+                               pInfo->state = R3964_WAIT_FOR_RX_BUF;
+                               mod_timer(&pInfo->tmr,
+                                         jiffies + R3964_TO_NO_BUF);
+                               break;
+                       }
+start_receiving:
+                       /* Ok, start receiving: */
+                       TRACE_PS("IDLE - got STX");
+                       pInfo->rx_position = 0;
+                       pInfo->last_rx = 0;
+                       pInfo->flags &= ~R3964_ERROR;
+                       pInfo->state = R3964_RECEIVING;
+                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
+                       pInfo->nRetry = 0;
+                       put_char(pInfo, DLE);
+                       flush(pInfo);
+                       pInfo->bcc = 0;
+               }
+               break;
+       case R3964_RECEIVING:
+               if (pInfo->rx_position < RX_BUF_SIZE) {
+                       pInfo->bcc ^= c;
+
+                       if (c == DLE) {
+                               if (pInfo->last_rx == DLE) {
+                                       pInfo->last_rx = 0;
+                                       goto char_to_buf;
+                               }
+                               pInfo->last_rx = DLE;
+                               break;
+                       } else if ((c == ETX) && (pInfo->last_rx == DLE)) {
+                               if (pInfo->flags & R3964_BCC) {
+                                       pInfo->state = R3964_WAIT_FOR_BCC;
+                                       mod_timer(&pInfo->tmr,
+                                                 jiffies + R3964_TO_ZVZ);
+                               } else {
+                                       on_receive_block(pInfo);
+                               }
+                       } else {
+                               pInfo->last_rx = c;
+char_to_buf:
+                               pInfo->rx_buf[pInfo->rx_position++] = c;
+                               mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
+                       }
+               }
+               /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */
+               break;
+       case R3964_WAIT_FOR_BCC:
+               pInfo->last_rx = c;
+               on_receive_block(pInfo);
+               break;
+       }
+}
+
+static void receive_error(struct r3964_info *pInfo, const char flag)
+{
+       switch (flag) {
+       case TTY_NORMAL:
+               break;
+       case TTY_BREAK:
+               TRACE_PE("received break");
+               pInfo->flags |= R3964_BREAK;
+               break;
+       case TTY_PARITY:
+               TRACE_PE("parity error");
+               pInfo->flags |= R3964_PARITY;
+               break;
+       case TTY_FRAME:
+               TRACE_PE("frame error");
+               pInfo->flags |= R3964_FRAME;
+               break;
+       case TTY_OVERRUN:
+               TRACE_PE("frame overrun");
+               pInfo->flags |= R3964_OVERRUN;
+               break;
+       default:
+               TRACE_PE("receive_error - unknown flag %d", flag);
+               pInfo->flags |= R3964_UNKNOWN;
+               break;
+       }
+}
+
+static void on_timeout(unsigned long priv)
+{
+       struct r3964_info *pInfo = (void *)priv;
+
+       switch (pInfo->state) {
+       case R3964_TX_REQUEST:
+               TRACE_PE("TX_REQUEST - timeout");
+               retry_transmit(pInfo);
+               break;
+       case R3964_WAIT_ZVZ_BEFORE_TX_RETRY:
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               retry_transmit(pInfo);
+               break;
+       case R3964_WAIT_FOR_TX_ACK:
+               TRACE_PE("WAIT_FOR_TX_ACK - timeout");
+               retry_transmit(pInfo);
+               break;
+       case R3964_WAIT_FOR_RX_BUF:
+               TRACE_PE("WAIT_FOR_RX_BUF - timeout");
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               pInfo->state = R3964_IDLE;
+               break;
+       case R3964_RECEIVING:
+               TRACE_PE("RECEIVING - timeout after %d chars",
+                        pInfo->rx_position);
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               pInfo->state = R3964_IDLE;
+               break;
+       case R3964_WAIT_FOR_RX_REPEAT:
+               TRACE_PE("WAIT_FOR_RX_REPEAT - timeout");
+               pInfo->state = R3964_IDLE;
+               break;
+       case R3964_WAIT_FOR_BCC:
+               TRACE_PE("WAIT_FOR_BCC - timeout");
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               pInfo->state = R3964_IDLE;
+               break;
+       }
+}
+
+static struct r3964_client_info *findClient(struct r3964_info *pInfo,
+               struct pid *pid)
+{
+       struct r3964_client_info *pClient;
+
+       for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
+               if (pClient->pid == pid) {
+                       return pClient;
+               }
+       }
+       return NULL;
+}
+
+static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg)
+{
+       struct r3964_client_info *pClient;
+       struct r3964_client_info **ppClient;
+       struct r3964_message *pMsg;
+
+       if ((arg & R3964_SIG_ALL) == 0) {
+               /* Remove client from client list */
+               for (ppClient = &pInfo->firstClient; *ppClient;
+                    ppClient = &(*ppClient)->next) {
+                       pClient = *ppClient;
+
+                       if (pClient->pid == pid) {
+                               TRACE_PS("removing client %d from client list",
+                                        pid_nr(pid));
+                               *ppClient = pClient->next;
+                               while (pClient->msg_count) {
+                                       pMsg = remove_msg(pInfo, pClient);
+                                       if (pMsg) {
+                                               kfree(pMsg);
+                                               TRACE_M("enable_signals - msg "
+                                                       "kfree %p", pMsg);
+                                       }
+                               }
+                               put_pid(pClient->pid);
+                               kfree(pClient);
+                               TRACE_M("enable_signals - kfree %p", pClient);
+                               return 0;
+                       }
+               }
+               return -EINVAL;
+       } else {
+               pClient = findClient(pInfo, pid);
+               if (pClient) {
+                       /* update signal options */
+                       pClient->sig_flags = arg;
+               } else {
+                       /* add client to client list */
+                       pClient = kmalloc(sizeof(struct r3964_client_info),
+                                       GFP_KERNEL);
+                       TRACE_M("enable_signals - kmalloc %p", pClient);
+                       if (pClient == NULL)
+                               return -ENOMEM;
+
+                       TRACE_PS("add client %d to client list", pid_nr(pid));
+                       spin_lock_init(&pClient->lock);
+                       pClient->sig_flags = arg;
+                       pClient->pid = get_pid(pid);
+                       pClient->next = pInfo->firstClient;
+                       pClient->first_msg = NULL;
+                       pClient->last_msg = NULL;
+                       pClient->next_block_to_read = NULL;
+                       pClient->msg_count = 0;
+                       pInfo->firstClient = pClient;
+               }
+       }
+
+       return 0;
+}
+
+static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
+                        unsigned char __user * buf)
+{
+       struct r3964_client_info *pClient;
+       struct r3964_block_header *block;
+
+       if (!buf) {
+               return -EINVAL;
+       }
+
+       pClient = findClient(pInfo, pid);
+       if (pClient == NULL) {
+               return -EINVAL;
+       }
+
+       block = pClient->next_block_to_read;
+       if (!block) {
+               return 0;
+       } else {
+               if (copy_to_user(buf, block->data, block->length))
+                       return -EFAULT;
+
+               remove_client_block(pInfo, pClient);
+               return block->length;
+       }
+
+       return -EINVAL;
+}
+
+static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
+               int error_code, struct r3964_block_header *pBlock)
+{
+       struct r3964_message *pMsg;
+       unsigned long flags;
+
+       if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) {
+queue_the_message:
+
+               pMsg = kmalloc(sizeof(struct r3964_message),
+                               error_code ? GFP_ATOMIC : GFP_KERNEL);
+               TRACE_M("add_msg - kmalloc %p", pMsg);
+               if (pMsg == NULL) {
+                       return;
+               }
+
+               spin_lock_irqsave(&pClient->lock, flags);
+
+               pMsg->msg_id = msg_id;
+               pMsg->arg = arg;
+               pMsg->error_code = error_code;
+               pMsg->block = pBlock;
+               pMsg->next = NULL;
+
+               if (pClient->last_msg == NULL) {
+                       pClient->first_msg = pClient->last_msg = pMsg;
+               } else {
+                       pClient->last_msg->next = pMsg;
+                       pClient->last_msg = pMsg;
+               }
+
+               pClient->msg_count++;
+
+               if (pBlock != NULL) {
+                       pBlock->locks++;
+               }
+               spin_unlock_irqrestore(&pClient->lock, flags);
+       } else {
+               if ((pClient->last_msg->msg_id == R3964_MSG_ACK)
+                   && (pClient->last_msg->error_code == R3964_OVERFLOW)) {
+                       pClient->last_msg->arg++;
+                       TRACE_PE("add_msg - inc prev OVERFLOW-msg");
+               } else {
+                       msg_id = R3964_MSG_ACK;
+                       arg = 0;
+                       error_code = R3964_OVERFLOW;
+                       pBlock = NULL;
+                       TRACE_PE("add_msg - queue OVERFLOW-msg");
+                       goto queue_the_message;
+               }
+       }
+       /* Send SIGIO signal to client process: */
+       if (pClient->sig_flags & R3964_USE_SIGIO) {
+               kill_pid(pClient->pid, SIGIO, 1);
+       }
+}
+
+static struct r3964_message *remove_msg(struct r3964_info *pInfo,
+                                       struct r3964_client_info *pClient)
+{
+       struct r3964_message *pMsg = NULL;
+       unsigned long flags;
+
+       if (pClient->first_msg) {
+               spin_lock_irqsave(&pClient->lock, flags);
+
+               pMsg = pClient->first_msg;
+               pClient->first_msg = pMsg->next;
+               if (pClient->first_msg == NULL) {
+                       pClient->last_msg = NULL;
+               }
+
+               pClient->msg_count--;
+               if (pMsg->block) {
+                       remove_client_block(pInfo, pClient);
+                       pClient->next_block_to_read = pMsg->block;
+               }
+               spin_unlock_irqrestore(&pClient->lock, flags);
+       }
+       return pMsg;
+}
+
+static void remove_client_block(struct r3964_info *pInfo,
+                               struct r3964_client_info *pClient)
+{
+       struct r3964_block_header *block;
+
+       TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid));
+
+       block = pClient->next_block_to_read;
+       if (block) {
+               block->locks--;
+               if (block->locks == 0) {
+                       remove_from_rx_queue(pInfo, block);
+               }
+       }
+       pClient->next_block_to_read = NULL;
+}
+
+/*************************************************************
+ * Line discipline routines
+ *************************************************************/
+
+static int r3964_open(struct tty_struct *tty)
+{
+       struct r3964_info *pInfo;
+
+       TRACE_L("open");
+       TRACE_L("tty=%p, PID=%d, disc_data=%p",
+               tty, current->pid, tty->disc_data);
+
+       pInfo = kmalloc(sizeof(struct r3964_info), GFP_KERNEL);
+       TRACE_M("r3964_open - info kmalloc %p", pInfo);
+
+       if (!pInfo) {
+               printk(KERN_ERR "r3964: failed to alloc info structure\n");
+               return -ENOMEM;
+       }
+
+       pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
+       TRACE_M("r3964_open - rx_buf kmalloc %p", pInfo->rx_buf);
+
+       if (!pInfo->rx_buf) {
+               printk(KERN_ERR "r3964: failed to alloc receive buffer\n");
+               kfree(pInfo);
+               TRACE_M("r3964_open - info kfree %p", pInfo);
+               return -ENOMEM;
+       }
+
+       pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL);
+       TRACE_M("r3964_open - tx_buf kmalloc %p", pInfo->tx_buf);
+
+       if (!pInfo->tx_buf) {
+               printk(KERN_ERR "r3964: failed to alloc transmit buffer\n");
+               kfree(pInfo->rx_buf);
+               TRACE_M("r3964_open - rx_buf kfree %p", pInfo->rx_buf);
+               kfree(pInfo);
+               TRACE_M("r3964_open - info kfree %p", pInfo);
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&pInfo->lock);
+       pInfo->tty = tty;
+       init_waitqueue_head(&pInfo->read_wait);
+       pInfo->priority = R3964_MASTER;
+       pInfo->rx_first = pInfo->rx_last = NULL;
+       pInfo->tx_first = pInfo->tx_last = NULL;
+       pInfo->rx_position = 0;
+       pInfo->tx_position = 0;
+       pInfo->last_rx = 0;
+       pInfo->blocks_in_rx_queue = 0;
+       pInfo->firstClient = NULL;
+       pInfo->state = R3964_IDLE;
+       pInfo->flags = R3964_DEBUG;
+       pInfo->nRetry = 0;
+
+       tty->disc_data = pInfo;
+       tty->receive_room = 65536;
+
+       setup_timer(&pInfo->tmr, on_timeout, (unsigned long)pInfo);
+
+       return 0;
+}
+
+static void r3964_close(struct tty_struct *tty)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       struct r3964_client_info *pClient, *pNext;
+       struct r3964_message *pMsg;
+       struct r3964_block_header *pHeader, *pNextHeader;
+       unsigned long flags;
+
+       TRACE_L("close");
+
+       /*
+        * Make sure that our task queue isn't activated.  If it
+        * is, take it out of the linked list.
+        */
+       del_timer_sync(&pInfo->tmr);
+
+       /* Remove client-structs and message queues: */
+       pClient = pInfo->firstClient;
+       while (pClient) {
+               pNext = pClient->next;
+               while (pClient->msg_count) {
+                       pMsg = remove_msg(pInfo, pClient);
+                       if (pMsg) {
+                               kfree(pMsg);
+                               TRACE_M("r3964_close - msg kfree %p", pMsg);
+                       }
+               }
+               put_pid(pClient->pid);
+               kfree(pClient);
+               TRACE_M("r3964_close - client kfree %p", pClient);
+               pClient = pNext;
+       }
+       /* Remove jobs from tx_queue: */
+       spin_lock_irqsave(&pInfo->lock, flags);
+       pHeader = pInfo->tx_first;
+       pInfo->tx_first = pInfo->tx_last = NULL;
+       spin_unlock_irqrestore(&pInfo->lock, flags);
+
+       while (pHeader) {
+               pNextHeader = pHeader->next;
+               kfree(pHeader);
+               pHeader = pNextHeader;
+       }
+
+       /* Free buffers: */
+       wake_up_interruptible(&pInfo->read_wait);
+       kfree(pInfo->rx_buf);
+       TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf);
+       kfree(pInfo->tx_buf);
+       TRACE_M("r3964_close - tx_buf kfree %p", pInfo->tx_buf);
+       kfree(pInfo);
+       TRACE_M("r3964_close - info kfree %p", pInfo);
+}
+
+static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
+                         unsigned char __user * buf, size_t nr)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       struct r3964_client_info *pClient;
+       struct r3964_message *pMsg;
+       struct r3964_client_message theMsg;
+       int ret;
+
+       TRACE_L("read()");
+
+       tty_lock();
+
+       pClient = findClient(pInfo, task_pid(current));
+       if (pClient) {
+               pMsg = remove_msg(pInfo, pClient);
+               if (pMsg == NULL) {
+                       /* no messages available. */
+                       if (file->f_flags & O_NONBLOCK) {
+                               ret = -EAGAIN;
+                               goto unlock;
+                       }
+                       /* block until there is a message: */
+                       wait_event_interruptible_tty(pInfo->read_wait,
+                                       (pMsg = remove_msg(pInfo, pClient)));
+               }
+
+               /* If we still haven't got a message, we must have been signalled */
+
+               if (!pMsg) {
+                       ret = -EINTR;
+                       goto unlock;
+               }
+
+               /* deliver msg to client process: */
+               theMsg.msg_id = pMsg->msg_id;
+               theMsg.arg = pMsg->arg;
+               theMsg.error_code = pMsg->error_code;
+               ret = sizeof(struct r3964_client_message);
+
+               kfree(pMsg);
+               TRACE_M("r3964_read - msg kfree %p", pMsg);
+
+               if (copy_to_user(buf, &theMsg, ret)) {
+                       ret = -EFAULT;
+                       goto unlock;
+               }
+
+               TRACE_PS("read - return %d", ret);
+               goto unlock;
+       }
+       ret = -EPERM;
+unlock:
+       tty_unlock();
+       return ret;
+}
+
+static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
+                          const unsigned char *data, size_t count)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       struct r3964_block_header *pHeader;
+       struct r3964_client_info *pClient;
+       unsigned char *new_data;
+
+       TRACE_L("write request, %d characters", count);
+/* 
+ * Verify the pointers 
+ */
+
+       if (!pInfo)
+               return -EIO;
+
+/*
+ * Ensure that the caller does not wish to send too much.
+ */
+       if (count > R3964_MTU) {
+               if (pInfo->flags & R3964_DEBUG) {
+                       TRACE_L(KERN_WARNING "r3964_write: truncating user "
+                               "packet from %u to mtu %d", count, R3964_MTU);
+               }
+               count = R3964_MTU;
+       }
+/*
+ * Allocate a buffer for the data and copy it from the buffer with header prepended
+ */
+       new_data = kmalloc(count + sizeof(struct r3964_block_header),
+                       GFP_KERNEL);
+       TRACE_M("r3964_write - kmalloc %p", new_data);
+       if (new_data == NULL) {
+               if (pInfo->flags & R3964_DEBUG) {
+                       printk(KERN_ERR "r3964_write: no memory\n");
+               }
+               return -ENOSPC;
+       }
+
+       pHeader = (struct r3964_block_header *)new_data;
+       pHeader->data = new_data + sizeof(struct r3964_block_header);
+       pHeader->length = count;
+       pHeader->locks = 0;
+       pHeader->owner = NULL;
+
+       tty_lock();
+
+       pClient = findClient(pInfo, task_pid(current));
+       if (pClient) {
+               pHeader->owner = pClient;
+       }
+
+       memcpy(pHeader->data, data, count);     /* We already verified this */
+
+       if (pInfo->flags & R3964_DEBUG) {
+               dump_block(pHeader->data, count);
+       }
+
+/*
+ * Add buffer to transmit-queue:
+ */
+       add_tx_queue(pInfo, pHeader);
+       trigger_transmit(pInfo);
+
+       tty_unlock();
+
+       return 0;
+}
+
+static int r3964_ioctl(struct tty_struct *tty, struct file *file,
+               unsigned int cmd, unsigned long arg)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       if (pInfo == NULL)
+               return -EINVAL;
+       switch (cmd) {
+       case R3964_ENABLE_SIGNALS:
+               return enable_signals(pInfo, task_pid(current), arg);
+       case R3964_SETPRIORITY:
+               if (arg < R3964_MASTER || arg > R3964_SLAVE)
+                       return -EINVAL;
+               pInfo->priority = arg & 0xff;
+               return 0;
+       case R3964_USE_BCC:
+               if (arg)
+                       pInfo->flags |= R3964_BCC;
+               else
+                       pInfo->flags &= ~R3964_BCC;
+               return 0;
+       case R3964_READ_TELEGRAM:
+               return read_telegram(pInfo, task_pid(current),
+                               (unsigned char __user *)arg);
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old)
+{
+       TRACE_L("set_termios");
+}
+
+/* Called without the kernel lock held - fine */
+static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
+                       struct poll_table_struct *wait)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       struct r3964_client_info *pClient;
+       struct r3964_message *pMsg = NULL;
+       unsigned long flags;
+       int result = POLLOUT;
+
+       TRACE_L("POLL");
+
+       pClient = findClient(pInfo, task_pid(current));
+       if (pClient) {
+               poll_wait(file, &pInfo->read_wait, wait);
+               spin_lock_irqsave(&pInfo->lock, flags);
+               pMsg = pClient->first_msg;
+               spin_unlock_irqrestore(&pInfo->lock, flags);
+               if (pMsg)
+                       result |= POLLIN | POLLRDNORM;
+       } else {
+               result = -EINVAL;
+       }
+       return result;
+}
+
+static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                       char *fp, int count)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       const unsigned char *p;
+       char *f, flags = 0;
+       int i;
+
+       for (i = count, p = cp, f = fp; i; i--, p++) {
+               if (f)
+                       flags = *f++;
+               if (flags == TTY_NORMAL) {
+                       receive_char(pInfo, *p);
+               } else {
+                       receive_error(pInfo, flags);
+               }
+
+       }
+}
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_LDISC(N_R3964);
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
new file mode 100644 (file)
index 0000000..428f4fe
--- /dev/null
@@ -0,0 +1,2121 @@
+/*
+ * n_tty.c --- implements the N_TTY line discipline.
+ *
+ * This code used to be in tty_io.c, but things are getting hairy
+ * enough that it made sense to split things off.  (The N_TTY
+ * processing has changed so much that it's hardly recognizable,
+ * anyway...)
+ *
+ * Note that the open routine for N_TTY is guaranteed never to return
+ * an error.  This is because Linux will fall back to setting a line
+ * to N_TTY if it can not switch to any other line discipline.
+ *
+ * Written by Theodore Ts'o, Copyright 1994.
+ *
+ * This file also contains code originally written by Linus Torvalds,
+ * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994.
+ *
+ * This file may be redistributed under the terms of the GNU General Public
+ * License.
+ *
+ * Reduced memory usage for older ARM systems  - Russell King.
+ *
+ * 2000/01/20   Fixed SMP locking on put_tty_queue using bits of
+ *             the patch by Andrew J. Kroll <ag784@freenet.buffalo.edu>
+ *             who actually finally proved there really was a race.
+ *
+ * 2002/03/18   Implemented n_tty_wakeup to send SIGIO POLL_OUTs to
+ *             waiting writing processes-Sapan Bhatia <sapan@corewars.org>.
+ *             Also fixed a bug in BLOCKING mode where n_tty_write returns
+ *             EAGAIN
+ */
+
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/bitops.h>
+#include <linux/audit.h>
+#include <linux/file.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+
+/* number of characters left in xmit buffer before select has we have room */
+#define WAKEUP_CHARS 256
+
+/*
+ * This defines the low- and high-watermarks for throttling and
+ * unthrottling the TTY driver.  These watermarks are used for
+ * controlling the space in the read buffer.
+ */
+#define TTY_THRESHOLD_THROTTLE         128 /* now based on remaining room */
+#define TTY_THRESHOLD_UNTHROTTLE       128
+
+/*
+ * Special byte codes used in the echo buffer to represent operations
+ * or special handling of characters.  Bytes in the echo buffer that
+ * are not part of such special blocks are treated as normal character
+ * codes.
+ */
+#define ECHO_OP_START 0xff
+#define ECHO_OP_MOVE_BACK_COL 0x80
+#define ECHO_OP_SET_CANON_COL 0x81
+#define ECHO_OP_ERASE_TAB 0x82
+
+static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
+                              unsigned char __user *ptr)
+{
+       tty_audit_add_data(tty, &x, 1);
+       return put_user(x, ptr);
+}
+
+/**
+ *     n_tty_set__room -       receive space
+ *     @tty: terminal
+ *
+ *     Called by the driver to find out how much data it is
+ *     permitted to feed to the line discipline without any being lost
+ *     and thus to manage flow control. Not serialized. Answers for the
+ *     "instant".
+ */
+
+static void n_tty_set_room(struct tty_struct *tty)
+{
+       /* tty->read_cnt is not read locked ? */
+       int     left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+
+       /*
+        * If we are doing input canonicalization, and there are no
+        * pending newlines, let characters through without limit, so
+        * that erase characters will be handled.  Other excess
+        * characters will be beeped.
+        */
+       if (left <= 0)
+               left = tty->icanon && !tty->canon_data;
+       tty->receive_room = left;
+}
+
+static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
+{
+       if (tty->read_cnt < N_TTY_BUF_SIZE) {
+               tty->read_buf[tty->read_head] = c;
+               tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
+               tty->read_cnt++;
+       }
+}
+
+/**
+ *     put_tty_queue           -       add character to tty
+ *     @c: character
+ *     @tty: tty device
+ *
+ *     Add a character to the tty read_buf queue. This is done under the
+ *     read_lock to serialize character addition and also to protect us
+ *     against parallel reads or flushes
+ */
+
+static void put_tty_queue(unsigned char c, struct tty_struct *tty)
+{
+       unsigned long flags;
+       /*
+        *      The problem of stomping on the buffers ends here.
+        *      Why didn't anyone see this one coming? --AJK
+       */
+       spin_lock_irqsave(&tty->read_lock, flags);
+       put_tty_queue_nolock(c, tty);
+       spin_unlock_irqrestore(&tty->read_lock, flags);
+}
+
+/**
+ *     check_unthrottle        -       allow new receive data
+ *     @tty; tty device
+ *
+ *     Check whether to call the driver unthrottle functions
+ *
+ *     Can sleep, may be called under the atomic_read_lock mutex but
+ *     this is not guaranteed.
+ */
+static void check_unthrottle(struct tty_struct *tty)
+{
+       if (tty->count)
+               tty_unthrottle(tty);
+}
+
+/**
+ *     reset_buffer_flags      -       reset buffer state
+ *     @tty: terminal to reset
+ *
+ *     Reset the read buffer counters, clear the flags,
+ *     and make sure the driver is unthrottled. Called
+ *     from n_tty_open() and n_tty_flush_buffer().
+ *
+ *     Locking: tty_read_lock for read fields.
+ */
+
+static void reset_buffer_flags(struct tty_struct *tty)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&tty->read_lock, flags);
+       tty->read_head = tty->read_tail = tty->read_cnt = 0;
+       spin_unlock_irqrestore(&tty->read_lock, flags);
+
+       mutex_lock(&tty->echo_lock);
+       tty->echo_pos = tty->echo_cnt = tty->echo_overrun = 0;
+       mutex_unlock(&tty->echo_lock);
+
+       tty->canon_head = tty->canon_data = tty->erasing = 0;
+       memset(&tty->read_flags, 0, sizeof tty->read_flags);
+       n_tty_set_room(tty);
+       check_unthrottle(tty);
+}
+
+/**
+ *     n_tty_flush_buffer      -       clean input queue
+ *     @tty:   terminal device
+ *
+ *     Flush the input buffer. Called when the line discipline is
+ *     being closed, when the tty layer wants the buffer flushed (eg
+ *     at hangup) or when the N_TTY line discipline internally has to
+ *     clean the pending queue (for example some signals).
+ *
+ *     Locking: ctrl_lock, read_lock.
+ */
+
+static void n_tty_flush_buffer(struct tty_struct *tty)
+{
+       unsigned long flags;
+       /* clear everything and unthrottle the driver */
+       reset_buffer_flags(tty);
+
+       if (!tty->link)
+               return;
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       if (tty->link->packet) {
+               tty->ctrl_status |= TIOCPKT_FLUSHREAD;
+               wake_up_interruptible(&tty->link->read_wait);
+       }
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+}
+
+/**
+ *     n_tty_chars_in_buffer   -       report available bytes
+ *     @tty: tty device
+ *
+ *     Report the number of characters buffered to be delivered to user
+ *     at this instant in time.
+ *
+ *     Locking: read_lock
+ */
+
+static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
+{
+       unsigned long flags;
+       ssize_t n = 0;
+
+       spin_lock_irqsave(&tty->read_lock, flags);
+       if (!tty->icanon) {
+               n = tty->read_cnt;
+       } else if (tty->canon_data) {
+               n = (tty->canon_head > tty->read_tail) ?
+                       tty->canon_head - tty->read_tail :
+                       tty->canon_head + (N_TTY_BUF_SIZE - tty->read_tail);
+       }
+       spin_unlock_irqrestore(&tty->read_lock, flags);
+       return n;
+}
+
+/**
+ *     is_utf8_continuation    -       utf8 multibyte check
+ *     @c: byte to check
+ *
+ *     Returns true if the utf8 character 'c' is a multibyte continuation
+ *     character. We use this to correctly compute the on screen size
+ *     of the character when printing
+ */
+
+static inline int is_utf8_continuation(unsigned char c)
+{
+       return (c & 0xc0) == 0x80;
+}
+
+/**
+ *     is_continuation         -       multibyte check
+ *     @c: byte to check
+ *
+ *     Returns true if the utf8 character 'c' is a multibyte continuation
+ *     character and the terminal is in unicode mode.
+ */
+
+static inline int is_continuation(unsigned char c, struct tty_struct *tty)
+{
+       return I_IUTF8(tty) && is_utf8_continuation(c);
+}
+
+/**
+ *     do_output_char                  -       output one character
+ *     @c: character (or partial unicode symbol)
+ *     @tty: terminal device
+ *     @space: space available in tty driver write buffer
+ *
+ *     This is a helper function that handles one output character
+ *     (including special characters like TAB, CR, LF, etc.),
+ *     doing OPOST processing and putting the results in the
+ *     tty driver's write buffer.
+ *
+ *     Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY
+ *     and NLDLY.  They simply aren't relevant in the world today.
+ *     If you ever need them, add them here.
+ *
+ *     Returns the number of bytes of buffer space used or -1 if
+ *     no space left.
+ *
+ *     Locking: should be called under the output_lock to protect
+ *              the column state and space left in the buffer
+ */
+
+static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
+{
+       int     spaces;
+
+       if (!space)
+               return -1;
+
+       switch (c) {
+       case '\n':
+               if (O_ONLRET(tty))
+                       tty->column = 0;
+               if (O_ONLCR(tty)) {
+                       if (space < 2)
+                               return -1;
+                       tty->canon_column = tty->column = 0;
+                       tty->ops->write(tty, "\r\n", 2);
+                       return 2;
+               }
+               tty->canon_column = tty->column;
+               break;
+       case '\r':
+               if (O_ONOCR(tty) && tty->column == 0)
+                       return 0;
+               if (O_OCRNL(tty)) {
+                       c = '\n';
+                       if (O_ONLRET(tty))
+                               tty->canon_column = tty->column = 0;
+                       break;
+               }
+               tty->canon_column = tty->column = 0;
+               break;
+       case '\t':
+               spaces = 8 - (tty->column & 7);
+               if (O_TABDLY(tty) == XTABS) {
+                       if (space < spaces)
+                               return -1;
+                       tty->column += spaces;
+                       tty->ops->write(tty, "        ", spaces);
+                       return spaces;
+               }
+               tty->column += spaces;
+               break;
+       case '\b':
+               if (tty->column > 0)
+                       tty->column--;
+               break;
+       default:
+               if (!iscntrl(c)) {
+                       if (O_OLCUC(tty))
+                               c = toupper(c);
+                       if (!is_continuation(c, tty))
+                               tty->column++;
+               }
+               break;
+       }
+
+       tty_put_char(tty, c);
+       return 1;
+}
+
+/**
+ *     process_output                  -       output post processor
+ *     @c: character (or partial unicode symbol)
+ *     @tty: terminal device
+ *
+ *     Output one character with OPOST processing.
+ *     Returns -1 when the output device is full and the character
+ *     must be retried.
+ *
+ *     Locking: output_lock to protect column state and space left
+ *              (also, this is called from n_tty_write under the
+ *               tty layer write lock)
+ */
+
+static int process_output(unsigned char c, struct tty_struct *tty)
+{
+       int     space, retval;
+
+       mutex_lock(&tty->output_lock);
+
+       space = tty_write_room(tty);
+       retval = do_output_char(c, tty, space);
+
+       mutex_unlock(&tty->output_lock);
+       if (retval < 0)
+               return -1;
+       else
+               return 0;
+}
+
+/**
+ *     process_output_block            -       block post processor
+ *     @tty: terminal device
+ *     @buf: character buffer
+ *     @nr: number of bytes to output
+ *
+ *     Output a block of characters with OPOST processing.
+ *     Returns the number of characters output.
+ *
+ *     This path is used to speed up block console writes, among other
+ *     things when processing blocks of output data. It handles only
+ *     the simple cases normally found and helps to generate blocks of
+ *     symbols for the console driver and thus improve performance.
+ *
+ *     Locking: output_lock to protect column state and space left
+ *              (also, this is called from n_tty_write under the
+ *               tty layer write lock)
+ */
+
+static ssize_t process_output_block(struct tty_struct *tty,
+                                   const unsigned char *buf, unsigned int nr)
+{
+       int     space;
+       int     i;
+       const unsigned char *cp;
+
+       mutex_lock(&tty->output_lock);
+
+       space = tty_write_room(tty);
+       if (!space) {
+               mutex_unlock(&tty->output_lock);
+               return 0;
+       }
+       if (nr > space)
+               nr = space;
+
+       for (i = 0, cp = buf; i < nr; i++, cp++) {
+               unsigned char c = *cp;
+
+               switch (c) {
+               case '\n':
+                       if (O_ONLRET(tty))
+                               tty->column = 0;
+                       if (O_ONLCR(tty))
+                               goto break_out;
+                       tty->canon_column = tty->column;
+                       break;
+               case '\r':
+                       if (O_ONOCR(tty) && tty->column == 0)
+                               goto break_out;
+                       if (O_OCRNL(tty))
+                               goto break_out;
+                       tty->canon_column = tty->column = 0;
+                       break;
+               case '\t':
+                       goto break_out;
+               case '\b':
+                       if (tty->column > 0)
+                               tty->column--;
+                       break;
+               default:
+                       if (!iscntrl(c)) {
+                               if (O_OLCUC(tty))
+                                       goto break_out;
+                               if (!is_continuation(c, tty))
+                                       tty->column++;
+                       }
+                       break;
+               }
+       }
+break_out:
+       i = tty->ops->write(tty, buf, i);
+
+       mutex_unlock(&tty->output_lock);
+       return i;
+}
+
+/**
+ *     process_echoes  -       write pending echo characters
+ *     @tty: terminal device
+ *
+ *     Write previously buffered echo (and other ldisc-generated)
+ *     characters to the tty.
+ *
+ *     Characters generated by the ldisc (including echoes) need to
+ *     be buffered because the driver's write buffer can fill during
+ *     heavy program output.  Echoing straight to the driver will
+ *     often fail under these conditions, causing lost characters and
+ *     resulting mismatches of ldisc state information.
+ *
+ *     Since the ldisc state must represent the characters actually sent
+ *     to the driver at the time of the write, operations like certain
+ *     changes in column state are also saved in the buffer and executed
+ *     here.
+ *
+ *     A circular fifo buffer is used so that the most recent characters
+ *     are prioritized.  Also, when control characters are echoed with a
+ *     prefixed "^", the pair is treated atomically and thus not separated.
+ *
+ *     Locking: output_lock to protect column state and space left,
+ *              echo_lock to protect the echo buffer
+ */
+
+static void process_echoes(struct tty_struct *tty)
+{
+       int     space, nr;
+       unsigned char c;
+       unsigned char *cp, *buf_end;
+
+       if (!tty->echo_cnt)
+               return;
+
+       mutex_lock(&tty->output_lock);
+       mutex_lock(&tty->echo_lock);
+
+       space = tty_write_room(tty);
+
+       buf_end = tty->echo_buf + N_TTY_BUF_SIZE;
+       cp = tty->echo_buf + tty->echo_pos;
+       nr = tty->echo_cnt;
+       while (nr > 0) {
+               c = *cp;
+               if (c == ECHO_OP_START) {
+                       unsigned char op;
+                       unsigned char *opp;
+                       int no_space_left = 0;
+
+                       /*
+                        * If the buffer byte is the start of a multi-byte
+                        * operation, get the next byte, which is either the
+                        * op code or a control character value.
+                        */
+                       opp = cp + 1;
+                       if (opp == buf_end)
+                               opp -= N_TTY_BUF_SIZE;
+                       op = *opp;
+
+                       switch (op) {
+                               unsigned int num_chars, num_bs;
+
+                       case ECHO_OP_ERASE_TAB:
+                               if (++opp == buf_end)
+                                       opp -= N_TTY_BUF_SIZE;
+                               num_chars = *opp;
+
+                               /*
+                                * Determine how many columns to go back
+                                * in order to erase the tab.
+                                * This depends on the number of columns
+                                * used by other characters within the tab
+                                * area.  If this (modulo 8) count is from
+                                * the start of input rather than from a
+                                * previous tab, we offset by canon column.
+                                * Otherwise, tab spacing is normal.
+                                */
+                               if (!(num_chars & 0x80))
+                                       num_chars += tty->canon_column;
+                               num_bs = 8 - (num_chars & 7);
+
+                               if (num_bs > space) {
+                                       no_space_left = 1;
+                                       break;
+                               }
+                               space -= num_bs;
+                               while (num_bs--) {
+                                       tty_put_char(tty, '\b');
+                                       if (tty->column > 0)
+                                               tty->column--;
+                               }
+                               cp += 3;
+                               nr -= 3;
+                               break;
+
+                       case ECHO_OP_SET_CANON_COL:
+                               tty->canon_column = tty->column;
+                               cp += 2;
+                               nr -= 2;
+                               break;
+
+                       case ECHO_OP_MOVE_BACK_COL:
+                               if (tty->column > 0)
+                                       tty->column--;
+                               cp += 2;
+                               nr -= 2;
+                               break;
+
+                       case ECHO_OP_START:
+                               /* This is an escaped echo op start code */
+                               if (!space) {
+                                       no_space_left = 1;
+                                       break;
+                               }
+                               tty_put_char(tty, ECHO_OP_START);
+                               tty->column++;
+                               space--;
+                               cp += 2;
+                               nr -= 2;
+                               break;
+
+                       default:
+                               /*
+                                * If the op is not a special byte code,
+                                * it is a ctrl char tagged to be echoed
+                                * as "^X" (where X is the letter
+                                * representing the control char).
+                                * Note that we must ensure there is
+                                * enough space for the whole ctrl pair.
+                                *
+                                */
+                               if (space < 2) {
+                                       no_space_left = 1;
+                                       break;
+                               }
+                               tty_put_char(tty, '^');
+                               tty_put_char(tty, op ^ 0100);
+                               tty->column += 2;
+                               space -= 2;
+                               cp += 2;
+                               nr -= 2;
+                       }
+
+                       if (no_space_left)
+                               break;
+               } else {
+                       if (O_OPOST(tty) &&
+                           !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
+                               int retval = do_output_char(c, tty, space);
+                               if (retval < 0)
+                                       break;
+                               space -= retval;
+                       } else {
+                               if (!space)
+                                       break;
+                               tty_put_char(tty, c);
+                               space -= 1;
+                       }
+                       cp += 1;
+                       nr -= 1;
+               }
+
+               /* When end of circular buffer reached, wrap around */
+               if (cp >= buf_end)
+                       cp -= N_TTY_BUF_SIZE;
+       }
+
+       if (nr == 0) {
+               tty->echo_pos = 0;
+               tty->echo_cnt = 0;
+               tty->echo_overrun = 0;
+       } else {
+               int num_processed = tty->echo_cnt - nr;
+               tty->echo_pos += num_processed;
+               tty->echo_pos &= N_TTY_BUF_SIZE - 1;
+               tty->echo_cnt = nr;
+               if (num_processed > 0)
+                       tty->echo_overrun = 0;
+       }
+
+       mutex_unlock(&tty->echo_lock);
+       mutex_unlock(&tty->output_lock);
+
+       if (tty->ops->flush_chars)
+               tty->ops->flush_chars(tty);
+}
+
+/**
+ *     add_echo_byte   -       add a byte to the echo buffer
+ *     @c: unicode byte to echo
+ *     @tty: terminal device
+ *
+ *     Add a character or operation byte to the echo buffer.
+ *
+ *     Should be called under the echo lock to protect the echo buffer.
+ */
+
+static void add_echo_byte(unsigned char c, struct tty_struct *tty)
+{
+       int     new_byte_pos;
+
+       if (tty->echo_cnt == N_TTY_BUF_SIZE) {
+               /* Circular buffer is already at capacity */
+               new_byte_pos = tty->echo_pos;
+
+               /*
+                * Since the buffer start position needs to be advanced,
+                * be sure to step by a whole operation byte group.
+                */
+               if (tty->echo_buf[tty->echo_pos] == ECHO_OP_START) {
+                       if (tty->echo_buf[(tty->echo_pos + 1) &
+                                         (N_TTY_BUF_SIZE - 1)] ==
+                                               ECHO_OP_ERASE_TAB) {
+                               tty->echo_pos += 3;
+                               tty->echo_cnt -= 2;
+                       } else {
+                               tty->echo_pos += 2;
+                               tty->echo_cnt -= 1;
+                       }
+               } else {
+                       tty->echo_pos++;
+               }
+               tty->echo_pos &= N_TTY_BUF_SIZE - 1;
+
+               tty->echo_overrun = 1;
+       } else {
+               new_byte_pos = tty->echo_pos + tty->echo_cnt;
+               new_byte_pos &= N_TTY_BUF_SIZE - 1;
+               tty->echo_cnt++;
+       }
+
+       tty->echo_buf[new_byte_pos] = c;
+}
+
+/**
+ *     echo_move_back_col      -       add operation to move back a column
+ *     @tty: terminal device
+ *
+ *     Add an operation to the echo buffer to move back one column.
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_move_back_col(struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       add_echo_byte(ECHO_OP_START, tty);
+       add_echo_byte(ECHO_OP_MOVE_BACK_COL, tty);
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     echo_set_canon_col      -       add operation to set the canon column
+ *     @tty: terminal device
+ *
+ *     Add an operation to the echo buffer to set the canon column
+ *     to the current column.
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_set_canon_col(struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       add_echo_byte(ECHO_OP_START, tty);
+       add_echo_byte(ECHO_OP_SET_CANON_COL, tty);
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     echo_erase_tab  -       add operation to erase a tab
+ *     @num_chars: number of character columns already used
+ *     @after_tab: true if num_chars starts after a previous tab
+ *     @tty: terminal device
+ *
+ *     Add an operation to the echo buffer to erase a tab.
+ *
+ *     Called by the eraser function, which knows how many character
+ *     columns have been used since either a previous tab or the start
+ *     of input.  This information will be used later, along with
+ *     canon column (if applicable), to go back the correct number
+ *     of columns.
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_erase_tab(unsigned int num_chars, int after_tab,
+                          struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       add_echo_byte(ECHO_OP_START, tty);
+       add_echo_byte(ECHO_OP_ERASE_TAB, tty);
+
+       /* We only need to know this modulo 8 (tab spacing) */
+       num_chars &= 7;
+
+       /* Set the high bit as a flag if num_chars is after a previous tab */
+       if (after_tab)
+               num_chars |= 0x80;
+
+       add_echo_byte(num_chars, tty);
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     echo_char_raw   -       echo a character raw
+ *     @c: unicode byte to echo
+ *     @tty: terminal device
+ *
+ *     Echo user input back onto the screen. This must be called only when
+ *     L_ECHO(tty) is true. Called from the driver receive_buf path.
+ *
+ *     This variant does not treat control characters specially.
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_char_raw(unsigned char c, struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       if (c == ECHO_OP_START) {
+               add_echo_byte(ECHO_OP_START, tty);
+               add_echo_byte(ECHO_OP_START, tty);
+       } else {
+               add_echo_byte(c, tty);
+       }
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     echo_char       -       echo a character
+ *     @c: unicode byte to echo
+ *     @tty: terminal device
+ *
+ *     Echo user input back onto the screen. This must be called only when
+ *     L_ECHO(tty) is true. Called from the driver receive_buf path.
+ *
+ *     This variant tags control characters to be echoed as "^X"
+ *     (where X is the letter representing the control char).
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_char(unsigned char c, struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       if (c == ECHO_OP_START) {
+               add_echo_byte(ECHO_OP_START, tty);
+               add_echo_byte(ECHO_OP_START, tty);
+       } else {
+               if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t')
+                       add_echo_byte(ECHO_OP_START, tty);
+               add_echo_byte(c, tty);
+       }
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     finish_erasing          -       complete erase
+ *     @tty: tty doing the erase
+ */
+
+static inline void finish_erasing(struct tty_struct *tty)
+{
+       if (tty->erasing) {
+               echo_char_raw('/', tty);
+               tty->erasing = 0;
+       }
+}
+
+/**
+ *     eraser          -       handle erase function
+ *     @c: character input
+ *     @tty: terminal device
+ *
+ *     Perform erase and necessary output when an erase character is
+ *     present in the stream from the driver layer. Handles the complexities
+ *     of UTF-8 multibyte symbols.
+ *
+ *     Locking: read_lock for tty buffers
+ */
+
+static void eraser(unsigned char c, struct tty_struct *tty)
+{
+       enum { ERASE, WERASE, KILL } kill_type;
+       int head, seen_alnums, cnt;
+       unsigned long flags;
+
+       /* FIXME: locking needed ? */
+       if (tty->read_head == tty->canon_head) {
+               /* process_output('\a', tty); */ /* what do you think? */
+               return;
+       }
+       if (c == ERASE_CHAR(tty))
+               kill_type = ERASE;
+       else if (c == WERASE_CHAR(tty))
+               kill_type = WERASE;
+       else {
+               if (!L_ECHO(tty)) {
+                       spin_lock_irqsave(&tty->read_lock, flags);
+                       tty->read_cnt -= ((tty->read_head - tty->canon_head) &
+                                         (N_TTY_BUF_SIZE - 1));
+                       tty->read_head = tty->canon_head;
+                       spin_unlock_irqrestore(&tty->read_lock, flags);
+                       return;
+               }
+               if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
+                       spin_lock_irqsave(&tty->read_lock, flags);
+                       tty->read_cnt -= ((tty->read_head - tty->canon_head) &
+                                         (N_TTY_BUF_SIZE - 1));
+                       tty->read_head = tty->canon_head;
+                       spin_unlock_irqrestore(&tty->read_lock, flags);
+                       finish_erasing(tty);
+                       echo_char(KILL_CHAR(tty), tty);
+                       /* Add a newline if ECHOK is on and ECHOKE is off. */
+                       if (L_ECHOK(tty))
+                               echo_char_raw('\n', tty);
+                       return;
+               }
+               kill_type = KILL;
+       }
+
+       seen_alnums = 0;
+       /* FIXME: Locking ?? */
+       while (tty->read_head != tty->canon_head) {
+               head = tty->read_head;
+
+               /* erase a single possibly multibyte character */
+               do {
+                       head = (head - 1) & (N_TTY_BUF_SIZE-1);
+                       c = tty->read_buf[head];
+               } while (is_continuation(c, tty) && head != tty->canon_head);
+
+               /* do not partially erase */
+               if (is_continuation(c, tty))
+                       break;
+
+               if (kill_type == WERASE) {
+                       /* Equivalent to BSD's ALTWERASE. */
+                       if (isalnum(c) || c == '_')
+                               seen_alnums++;
+                       else if (seen_alnums)
+                               break;
+               }
+               cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1);
+               spin_lock_irqsave(&tty->read_lock, flags);
+               tty->read_head = head;
+               tty->read_cnt -= cnt;
+               spin_unlock_irqrestore(&tty->read_lock, flags);
+               if (L_ECHO(tty)) {
+                       if (L_ECHOPRT(tty)) {
+                               if (!tty->erasing) {
+                                       echo_char_raw('\\', tty);
+                                       tty->erasing = 1;
+                               }
+                               /* if cnt > 1, output a multi-byte character */
+                               echo_char(c, tty);
+                               while (--cnt > 0) {
+                                       head = (head+1) & (N_TTY_BUF_SIZE-1);
+                                       echo_char_raw(tty->read_buf[head], tty);
+                                       echo_move_back_col(tty);
+                               }
+                       } else if (kill_type == ERASE && !L_ECHOE(tty)) {
+                               echo_char(ERASE_CHAR(tty), tty);
+                       } else if (c == '\t') {
+                               unsigned int num_chars = 0;
+                               int after_tab = 0;
+                               unsigned long tail = tty->read_head;
+
+                               /*
+                                * Count the columns used for characters
+                                * since the start of input or after a
+                                * previous tab.
+                                * This info is used to go back the correct
+                                * number of columns.
+                                */
+                               while (tail != tty->canon_head) {
+                                       tail = (tail-1) & (N_TTY_BUF_SIZE-1);
+                                       c = tty->read_buf[tail];
+                                       if (c == '\t') {
+                                               after_tab = 1;
+                                               break;
+                                       } else if (iscntrl(c)) {
+                                               if (L_ECHOCTL(tty))
+                                                       num_chars += 2;
+                                       } else if (!is_continuation(c, tty)) {
+                                               num_chars++;
+                                       }
+                               }
+                               echo_erase_tab(num_chars, after_tab, tty);
+                       } else {
+                               if (iscntrl(c) && L_ECHOCTL(tty)) {
+                                       echo_char_raw('\b', tty);
+                                       echo_char_raw(' ', tty);
+                                       echo_char_raw('\b', tty);
+                               }
+                               if (!iscntrl(c) || L_ECHOCTL(tty)) {
+                                       echo_char_raw('\b', tty);
+                                       echo_char_raw(' ', tty);
+                                       echo_char_raw('\b', tty);
+                               }
+                       }
+               }
+               if (kill_type == ERASE)
+                       break;
+       }
+       if (tty->read_head == tty->canon_head && L_ECHO(tty))
+               finish_erasing(tty);
+}
+
+/**
+ *     isig            -       handle the ISIG optio
+ *     @sig: signal
+ *     @tty: terminal
+ *     @flush: force flush
+ *
+ *     Called when a signal is being sent due to terminal input. This
+ *     may caus terminal flushing to take place according to the termios
+ *     settings and character used. Called from the driver receive_buf
+ *     path so serialized.
+ *
+ *     Locking: ctrl_lock, read_lock (both via flush buffer)
+ */
+
+static inline void isig(int sig, struct tty_struct *tty, int flush)
+{
+       if (tty->pgrp)
+               kill_pgrp(tty->pgrp, sig, 1);
+       if (flush || !L_NOFLSH(tty)) {
+               n_tty_flush_buffer(tty);
+               tty_driver_flush_buffer(tty);
+       }
+}
+
+/**
+ *     n_tty_receive_break     -       handle break
+ *     @tty: terminal
+ *
+ *     An RS232 break event has been hit in the incoming bitstream. This
+ *     can cause a variety of events depending upon the termios settings.
+ *
+ *     Called from the receive_buf path so single threaded.
+ */
+
+static inline void n_tty_receive_break(struct tty_struct *tty)
+{
+       if (I_IGNBRK(tty))
+               return;
+       if (I_BRKINT(tty)) {
+               isig(SIGINT, tty, 1);
+               return;
+       }
+       if (I_PARMRK(tty)) {
+               put_tty_queue('\377', tty);
+               put_tty_queue('\0', tty);
+       }
+       put_tty_queue('\0', tty);
+       wake_up_interruptible(&tty->read_wait);
+}
+
+/**
+ *     n_tty_receive_overrun   -       handle overrun reporting
+ *     @tty: terminal
+ *
+ *     Data arrived faster than we could process it. While the tty
+ *     driver has flagged this the bits that were missed are gone
+ *     forever.
+ *
+ *     Called from the receive_buf path so single threaded. Does not
+ *     need locking as num_overrun and overrun_time are function
+ *     private.
+ */
+
+static inline void n_tty_receive_overrun(struct tty_struct *tty)
+{
+       char buf[64];
+
+       tty->num_overrun++;
+       if (time_before(tty->overrun_time, jiffies - HZ) ||
+                       time_after(tty->overrun_time, jiffies)) {
+               printk(KERN_WARNING "%s: %d input overrun(s)\n",
+                       tty_name(tty, buf),
+                       tty->num_overrun);
+               tty->overrun_time = jiffies;
+               tty->num_overrun = 0;
+       }
+}
+
+/**
+ *     n_tty_receive_parity_error      -       error notifier
+ *     @tty: terminal device
+ *     @c: character
+ *
+ *     Process a parity error and queue the right data to indicate
+ *     the error case if necessary. Locking as per n_tty_receive_buf.
+ */
+static inline void n_tty_receive_parity_error(struct tty_struct *tty,
+                                             unsigned char c)
+{
+       if (I_IGNPAR(tty))
+               return;
+       if (I_PARMRK(tty)) {
+               put_tty_queue('\377', tty);
+               put_tty_queue('\0', tty);
+               put_tty_queue(c, tty);
+       } else  if (I_INPCK(tty))
+               put_tty_queue('\0', tty);
+       else
+               put_tty_queue(c, tty);
+       wake_up_interruptible(&tty->read_wait);
+}
+
+/**
+ *     n_tty_receive_char      -       perform processing
+ *     @tty: terminal device
+ *     @c: character
+ *
+ *     Process an individual character of input received from the driver.
+ *     This is serialized with respect to itself by the rules for the
+ *     driver above.
+ */
+
+static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
+{
+       unsigned long flags;
+       int parmrk;
+
+       if (tty->raw) {
+               put_tty_queue(c, tty);
+               return;
+       }
+
+       if (I_ISTRIP(tty))
+               c &= 0x7f;
+       if (I_IUCLC(tty) && L_IEXTEN(tty))
+               c = tolower(c);
+
+       if (L_EXTPROC(tty)) {
+               put_tty_queue(c, tty);
+               return;
+       }
+
+       if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
+           I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty) &&
+           c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty)) {
+               start_tty(tty);
+               process_echoes(tty);
+       }
+
+       if (tty->closing) {
+               if (I_IXON(tty)) {
+                       if (c == START_CHAR(tty)) {
+                               start_tty(tty);
+                               process_echoes(tty);
+                       } else if (c == STOP_CHAR(tty))
+                               stop_tty(tty);
+               }
+               return;
+       }
+
+       /*
+        * If the previous character was LNEXT, or we know that this
+        * character is not one of the characters that we'll have to
+        * handle specially, do shortcut processing to speed things
+        * up.
+        */
+       if (!test_bit(c, tty->process_char_map) || tty->lnext) {
+               tty->lnext = 0;
+               parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
+               if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
+                       /* beep if no space */
+                       if (L_ECHO(tty))
+                               process_output('\a', tty);
+                       return;
+               }
+               if (L_ECHO(tty)) {
+                       finish_erasing(tty);
+                       /* Record the column of first canon char. */
+                       if (tty->canon_head == tty->read_head)
+                               echo_set_canon_col(tty);
+                       echo_char(c, tty);
+                       process_echoes(tty);
+               }
+               if (parmrk)
+                       put_tty_queue(c, tty);
+               put_tty_queue(c, tty);
+               return;
+       }
+
+       if (I_IXON(tty)) {
+               if (c == START_CHAR(tty)) {
+                       start_tty(tty);
+                       process_echoes(tty);
+                       return;
+               }
+               if (c == STOP_CHAR(tty)) {
+                       stop_tty(tty);
+                       return;
+               }
+       }
+
+       if (L_ISIG(tty)) {
+               int signal;
+               signal = SIGINT;
+               if (c == INTR_CHAR(tty))
+                       goto send_signal;
+               signal = SIGQUIT;
+               if (c == QUIT_CHAR(tty))
+                       goto send_signal;
+               signal = SIGTSTP;
+               if (c == SUSP_CHAR(tty)) {
+send_signal:
+                       /*
+                        * Note that we do not use isig() here because we want
+                        * the order to be:
+                        * 1) flush, 2) echo, 3) signal
+                        */
+                       if (!L_NOFLSH(tty)) {
+                               n_tty_flush_buffer(tty);
+                               tty_driver_flush_buffer(tty);
+                       }
+                       if (I_IXON(tty))
+                               start_tty(tty);
+                       if (L_ECHO(tty)) {
+                               echo_char(c, tty);
+                               process_echoes(tty);
+                       }
+                       if (tty->pgrp)
+                               kill_pgrp(tty->pgrp, signal, 1);
+                       return;
+               }
+       }
+
+       if (c == '\r') {
+               if (I_IGNCR(tty))
+                       return;
+               if (I_ICRNL(tty))
+                       c = '\n';
+       } else if (c == '\n' && I_INLCR(tty))
+               c = '\r';
+
+       if (tty->icanon) {
+               if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
+                   (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
+                       eraser(c, tty);
+                       process_echoes(tty);
+                       return;
+               }
+               if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
+                       tty->lnext = 1;
+                       if (L_ECHO(tty)) {
+                               finish_erasing(tty);
+                               if (L_ECHOCTL(tty)) {
+                                       echo_char_raw('^', tty);
+                                       echo_char_raw('\b', tty);
+                                       process_echoes(tty);
+                               }
+                       }
+                       return;
+               }
+               if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
+                   L_IEXTEN(tty)) {
+                       unsigned long tail = tty->canon_head;
+
+                       finish_erasing(tty);
+                       echo_char(c, tty);
+                       echo_char_raw('\n', tty);
+                       while (tail != tty->read_head) {
+                               echo_char(tty->read_buf[tail], tty);
+                               tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+                       }
+                       process_echoes(tty);
+                       return;
+               }
+               if (c == '\n') {
+                       if (tty->read_cnt >= N_TTY_BUF_SIZE) {
+                               if (L_ECHO(tty))
+                                       process_output('\a', tty);
+                               return;
+                       }
+                       if (L_ECHO(tty) || L_ECHONL(tty)) {
+                               echo_char_raw('\n', tty);
+                               process_echoes(tty);
+                       }
+                       goto handle_newline;
+               }
+               if (c == EOF_CHAR(tty)) {
+                       if (tty->read_cnt >= N_TTY_BUF_SIZE)
+                               return;
+                       if (tty->canon_head != tty->read_head)
+                               set_bit(TTY_PUSH, &tty->flags);
+                       c = __DISABLED_CHAR;
+                       goto handle_newline;
+               }
+               if ((c == EOL_CHAR(tty)) ||
+                   (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
+                       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
+                                ? 1 : 0;
+                       if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
+                               if (L_ECHO(tty))
+                                       process_output('\a', tty);
+                               return;
+                       }
+                       /*
+                        * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
+                        */
+                       if (L_ECHO(tty)) {
+                               /* Record the column of first canon char. */
+                               if (tty->canon_head == tty->read_head)
+                                       echo_set_canon_col(tty);
+                               echo_char(c, tty);
+                               process_echoes(tty);
+                       }
+                       /*
+                        * XXX does PARMRK doubling happen for
+                        * EOL_CHAR and EOL2_CHAR?
+                        */
+                       if (parmrk)
+                               put_tty_queue(c, tty);
+
+handle_newline:
+                       spin_lock_irqsave(&tty->read_lock, flags);
+                       set_bit(tty->read_head, tty->read_flags);
+                       put_tty_queue_nolock(c, tty);
+                       tty->canon_head = tty->read_head;
+                       tty->canon_data++;
+                       spin_unlock_irqrestore(&tty->read_lock, flags);
+                       kill_fasync(&tty->fasync, SIGIO, POLL_IN);
+                       if (waitqueue_active(&tty->read_wait))
+                               wake_up_interruptible(&tty->read_wait);
+                       return;
+               }
+       }
+
+       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
+       if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
+               /* beep if no space */
+               if (L_ECHO(tty))
+                       process_output('\a', tty);
+               return;
+       }
+       if (L_ECHO(tty)) {
+               finish_erasing(tty);
+               if (c == '\n')
+                       echo_char_raw('\n', tty);
+               else {
+                       /* Record the column of first canon char. */
+                       if (tty->canon_head == tty->read_head)
+                               echo_set_canon_col(tty);
+                       echo_char(c, tty);
+               }
+               process_echoes(tty);
+       }
+
+       if (parmrk)
+               put_tty_queue(c, tty);
+
+       put_tty_queue(c, tty);
+}
+
+
+/**
+ *     n_tty_write_wakeup      -       asynchronous I/O notifier
+ *     @tty: tty device
+ *
+ *     Required for the ptys, serial driver etc. since processes
+ *     that attach themselves to the master and rely on ASYNC
+ *     IO must be woken up
+ */
+
+static void n_tty_write_wakeup(struct tty_struct *tty)
+{
+       if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
+               kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
+}
+
+/**
+ *     n_tty_receive_buf       -       data receive
+ *     @tty: terminal device
+ *     @cp: buffer
+ *     @fp: flag buffer
+ *     @count: characters
+ *
+ *     Called by the terminal driver when a block of characters has
+ *     been received. This function must be called from soft contexts
+ *     not from interrupt context. The driver is responsible for making
+ *     calls one at a time and in order (or using flush_to_ldisc)
+ */
+
+static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                             char *fp, int count)
+{
+       const unsigned char *p;
+       char *f, flags = TTY_NORMAL;
+       int     i;
+       char    buf[64];
+       unsigned long cpuflags;
+
+       if (!tty->read_buf)
+               return;
+
+       if (tty->real_raw) {
+               spin_lock_irqsave(&tty->read_lock, cpuflags);
+               i = min(N_TTY_BUF_SIZE - tty->read_cnt,
+                       N_TTY_BUF_SIZE - tty->read_head);
+               i = min(count, i);
+               memcpy(tty->read_buf + tty->read_head, cp, i);
+               tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
+               tty->read_cnt += i;
+               cp += i;
+               count -= i;
+
+               i = min(N_TTY_BUF_SIZE - tty->read_cnt,
+                       N_TTY_BUF_SIZE - tty->read_head);
+               i = min(count, i);
+               memcpy(tty->read_buf + tty->read_head, cp, i);
+               tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
+               tty->read_cnt += i;
+               spin_unlock_irqrestore(&tty->read_lock, cpuflags);
+       } else {
+               for (i = count, p = cp, f = fp; i; i--, p++) {
+                       if (f)
+                               flags = *f++;
+                       switch (flags) {
+                       case TTY_NORMAL:
+                               n_tty_receive_char(tty, *p);
+                               break;
+                       case TTY_BREAK:
+                               n_tty_receive_break(tty);
+                               break;
+                       case TTY_PARITY:
+                       case TTY_FRAME:
+                               n_tty_receive_parity_error(tty, *p);
+                               break;
+                       case TTY_OVERRUN:
+                               n_tty_receive_overrun(tty);
+                               break;
+                       default:
+                               printk(KERN_ERR "%s: unknown flag %d\n",
+                                      tty_name(tty, buf), flags);
+                               break;
+                       }
+               }
+               if (tty->ops->flush_chars)
+                       tty->ops->flush_chars(tty);
+       }
+
+       n_tty_set_room(tty);
+
+       if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) ||
+               L_EXTPROC(tty)) {
+               kill_fasync(&tty->fasync, SIGIO, POLL_IN);
+               if (waitqueue_active(&tty->read_wait))
+                       wake_up_interruptible(&tty->read_wait);
+       }
+
+       /*
+        * Check the remaining room for the input canonicalization
+        * mode.  We don't want to throttle the driver if we're in
+        * canonical mode and don't have a newline yet!
+        */
+       if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
+               tty_throttle(tty);
+}
+
+int is_ignored(int sig)
+{
+       return (sigismember(&current->blocked, sig) ||
+               current->sighand->action[sig-1].sa.sa_handler == SIG_IGN);
+}
+
+/**
+ *     n_tty_set_termios       -       termios data changed
+ *     @tty: terminal
+ *     @old: previous data
+ *
+ *     Called by the tty layer when the user changes termios flags so
+ *     that the line discipline can plan ahead. This function cannot sleep
+ *     and is protected from re-entry by the tty layer. The user is
+ *     guaranteed that this function will not be re-entered or in progress
+ *     when the ldisc is closed.
+ *
+ *     Locking: Caller holds tty->termios_mutex
+ */
+
+static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
+{
+       int canon_change = 1;
+       BUG_ON(!tty);
+
+       if (old)
+               canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
+       if (canon_change) {
+               memset(&tty->read_flags, 0, sizeof tty->read_flags);
+               tty->canon_head = tty->read_tail;
+               tty->canon_data = 0;
+               tty->erasing = 0;
+       }
+
+       if (canon_change && !L_ICANON(tty) && tty->read_cnt)
+               wake_up_interruptible(&tty->read_wait);
+
+       tty->icanon = (L_ICANON(tty) != 0);
+       if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
+               tty->raw = 1;
+               tty->real_raw = 1;
+               n_tty_set_room(tty);
+               return;
+       }
+       if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
+           I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
+           I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
+           I_PARMRK(tty)) {
+               memset(tty->process_char_map, 0, 256/8);
+
+               if (I_IGNCR(tty) || I_ICRNL(tty))
+                       set_bit('\r', tty->process_char_map);
+               if (I_INLCR(tty))
+                       set_bit('\n', tty->process_char_map);
+
+               if (L_ICANON(tty)) {
+                       set_bit(ERASE_CHAR(tty), tty->process_char_map);
+                       set_bit(KILL_CHAR(tty), tty->process_char_map);
+                       set_bit(EOF_CHAR(tty), tty->process_char_map);
+                       set_bit('\n', tty->process_char_map);
+                       set_bit(EOL_CHAR(tty), tty->process_char_map);
+                       if (L_IEXTEN(tty)) {
+                               set_bit(WERASE_CHAR(tty),
+                                       tty->process_char_map);
+                               set_bit(LNEXT_CHAR(tty),
+                                       tty->process_char_map);
+                               set_bit(EOL2_CHAR(tty),
+                                       tty->process_char_map);
+                               if (L_ECHO(tty))
+                                       set_bit(REPRINT_CHAR(tty),
+                                               tty->process_char_map);
+                       }
+               }
+               if (I_IXON(tty)) {
+                       set_bit(START_CHAR(tty), tty->process_char_map);
+                       set_bit(STOP_CHAR(tty), tty->process_char_map);
+               }
+               if (L_ISIG(tty)) {
+                       set_bit(INTR_CHAR(tty), tty->process_char_map);
+                       set_bit(QUIT_CHAR(tty), tty->process_char_map);
+                       set_bit(SUSP_CHAR(tty), tty->process_char_map);
+               }
+               clear_bit(__DISABLED_CHAR, tty->process_char_map);
+               tty->raw = 0;
+               tty->real_raw = 0;
+       } else {
+               tty->raw = 1;
+               if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
+                   (I_IGNPAR(tty) || !I_INPCK(tty)) &&
+                   (tty->driver->flags & TTY_DRIVER_REAL_RAW))
+                       tty->real_raw = 1;
+               else
+                       tty->real_raw = 0;
+       }
+       n_tty_set_room(tty);
+       /* The termios change make the tty ready for I/O */
+       wake_up_interruptible(&tty->write_wait);
+       wake_up_interruptible(&tty->read_wait);
+}
+
+/**
+ *     n_tty_close             -       close the ldisc for this tty
+ *     @tty: device
+ *
+ *     Called from the terminal layer when this line discipline is
+ *     being shut down, either because of a close or becsuse of a
+ *     discipline change. The function will not be called while other
+ *     ldisc methods are in progress.
+ */
+
+static void n_tty_close(struct tty_struct *tty)
+{
+       n_tty_flush_buffer(tty);
+       if (tty->read_buf) {
+               kfree(tty->read_buf);
+               tty->read_buf = NULL;
+       }
+       if (tty->echo_buf) {
+               kfree(tty->echo_buf);
+               tty->echo_buf = NULL;
+       }
+}
+
+/**
+ *     n_tty_open              -       open an ldisc
+ *     @tty: terminal to open
+ *
+ *     Called when this line discipline is being attached to the
+ *     terminal device. Can sleep. Called serialized so that no
+ *     other events will occur in parallel. No further open will occur
+ *     until a close.
+ */
+
+static int n_tty_open(struct tty_struct *tty)
+{
+       if (!tty)
+               return -EINVAL;
+
+       /* These are ugly. Currently a malloc failure here can panic */
+       if (!tty->read_buf) {
+               tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+               if (!tty->read_buf)
+                       return -ENOMEM;
+       }
+       if (!tty->echo_buf) {
+               tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+
+               if (!tty->echo_buf)
+                       return -ENOMEM;
+       }
+       reset_buffer_flags(tty);
+       tty->column = 0;
+       n_tty_set_termios(tty, NULL);
+       tty->minimum_to_wake = 1;
+       tty->closing = 0;
+       return 0;
+}
+
+static inline int input_available_p(struct tty_struct *tty, int amt)
+{
+       tty_flush_to_ldisc(tty);
+       if (tty->icanon && !L_EXTPROC(tty)) {
+               if (tty->canon_data)
+                       return 1;
+       } else if (tty->read_cnt >= (amt ? amt : 1))
+               return 1;
+
+       return 0;
+}
+
+/**
+ *     copy_from_read_buf      -       copy read data directly
+ *     @tty: terminal device
+ *     @b: user data
+ *     @nr: size of data
+ *
+ *     Helper function to speed up n_tty_read.  It is only called when
+ *     ICANON is off; it copies characters straight from the tty queue to
+ *     user space directly.  It can be profitably called twice; once to
+ *     drain the space from the tail pointer to the (physical) end of the
+ *     buffer, and once to drain the space from the (physical) beginning of
+ *     the buffer to head pointer.
+ *
+ *     Called under the tty->atomic_read_lock sem
+ *
+ */
+
+static int copy_from_read_buf(struct tty_struct *tty,
+                                     unsigned char __user **b,
+                                     size_t *nr)
+
+{
+       int retval;
+       size_t n;
+       unsigned long flags;
+
+       retval = 0;
+       spin_lock_irqsave(&tty->read_lock, flags);
+       n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail);
+       n = min(*nr, n);
+       spin_unlock_irqrestore(&tty->read_lock, flags);
+       if (n) {
+               retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
+               n -= retval;
+               tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
+               spin_lock_irqsave(&tty->read_lock, flags);
+               tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
+               tty->read_cnt -= n;
+               /* Turn single EOF into zero-length read */
+               if (L_EXTPROC(tty) && tty->icanon && n == 1) {
+                       if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
+                               n--;
+               }
+               spin_unlock_irqrestore(&tty->read_lock, flags);
+               *b += n;
+               *nr -= n;
+       }
+       return retval;
+}
+
+extern ssize_t redirected_tty_write(struct file *, const char __user *,
+                                                       size_t, loff_t *);
+
+/**
+ *     job_control             -       check job control
+ *     @tty: tty
+ *     @file: file handle
+ *
+ *     Perform job control management checks on this file/tty descriptor
+ *     and if appropriate send any needed signals and return a negative
+ *     error code if action should be taken.
+ *
+ *     FIXME:
+ *     Locking: None - redirected write test is safe, testing
+ *     current->signal should possibly lock current->sighand
+ *     pgrp locking ?
+ */
+
+static int job_control(struct tty_struct *tty, struct file *file)
+{
+       /* Job control check -- must be done at start and after
+          every sleep (POSIX.1 7.1.1.4). */
+       /* NOTE: not yet done after every sleep pending a thorough
+          check of the logic of this change. -- jlc */
+       /* don't stop on /dev/console */
+       if (file->f_op->write != redirected_tty_write &&
+           current->signal->tty == tty) {
+               if (!tty->pgrp)
+                       printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
+               else if (task_pgrp(current) != tty->pgrp) {
+                       if (is_ignored(SIGTTIN) ||
+                           is_current_pgrp_orphaned())
+                               return -EIO;
+                       kill_pgrp(task_pgrp(current), SIGTTIN, 1);
+                       set_thread_flag(TIF_SIGPENDING);
+                       return -ERESTARTSYS;
+               }
+       }
+       return 0;
+}
+
+
+/**
+ *     n_tty_read              -       read function for tty
+ *     @tty: tty device
+ *     @file: file object
+ *     @buf: userspace buffer pointer
+ *     @nr: size of I/O
+ *
+ *     Perform reads for the line discipline. We are guaranteed that the
+ *     line discipline will not be closed under us but we may get multiple
+ *     parallel readers and must handle this ourselves. We may also get
+ *     a hangup. Always called in user context, may sleep.
+ *
+ *     This code must be sure never to sleep through a hangup.
+ */
+
+static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
+                        unsigned char __user *buf, size_t nr)
+{
+       unsigned char __user *b = buf;
+       DECLARE_WAITQUEUE(wait, current);
+       int c;
+       int minimum, time;
+       ssize_t retval = 0;
+       ssize_t size;
+       long timeout;
+       unsigned long flags;
+       int packet;
+
+do_it_again:
+
+       BUG_ON(!tty->read_buf);
+
+       c = job_control(tty, file);
+       if (c < 0)
+               return c;
+
+       minimum = time = 0;
+       timeout = MAX_SCHEDULE_TIMEOUT;
+       if (!tty->icanon) {
+               time = (HZ / 10) * TIME_CHAR(tty);
+               minimum = MIN_CHAR(tty);
+               if (minimum) {
+                       if (time)
+                               tty->minimum_to_wake = 1;
+                       else if (!waitqueue_active(&tty->read_wait) ||
+                                (tty->minimum_to_wake > minimum))
+                               tty->minimum_to_wake = minimum;
+               } else {
+                       timeout = 0;
+                       if (time) {
+                               timeout = time;
+                               time = 0;
+                       }
+                       tty->minimum_to_wake = minimum = 1;
+               }
+       }
+
+       /*
+        *      Internal serialization of reads.
+        */
+       if (file->f_flags & O_NONBLOCK) {
+               if (!mutex_trylock(&tty->atomic_read_lock))
+                       return -EAGAIN;
+       } else {
+               if (mutex_lock_interruptible(&tty->atomic_read_lock))
+                       return -ERESTARTSYS;
+       }
+       packet = tty->packet;
+
+       add_wait_queue(&tty->read_wait, &wait);
+       while (nr) {
+               /* First test for status change. */
+               if (packet && tty->link->ctrl_status) {
+                       unsigned char cs;
+                       if (b != buf)
+                               break;
+                       spin_lock_irqsave(&tty->link->ctrl_lock, flags);
+                       cs = tty->link->ctrl_status;
+                       tty->link->ctrl_status = 0;
+                       spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
+                       if (tty_put_user(tty, cs, b++)) {
+                               retval = -EFAULT;
+                               b--;
+                               break;
+                       }
+                       nr--;
+                       break;
+               }
+               /* This statement must be first before checking for input
+                  so that any interrupt will set the state back to
+                  TASK_RUNNING. */
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
+                   ((minimum - (b - buf)) >= 1))
+                       tty->minimum_to_wake = (minimum - (b - buf));
+
+               if (!input_available_p(tty, 0)) {
+                       if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
+                               retval = -EIO;
+                               break;
+                       }
+                       if (tty_hung_up_p(file))
+                               break;
+                       if (!timeout)
+                               break;
+                       if (file->f_flags & O_NONBLOCK) {
+                               retval = -EAGAIN;
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               retval = -ERESTARTSYS;
+                               break;
+                       }
+                       /* FIXME: does n_tty_set_room need locking ? */
+                       n_tty_set_room(tty);
+                       timeout = schedule_timeout(timeout);
+                       continue;
+               }
+               __set_current_state(TASK_RUNNING);
+
+               /* Deal with packet mode. */
+               if (packet && b == buf) {
+                       if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
+                               retval = -EFAULT;
+                               b--;
+                               break;
+                       }
+                       nr--;
+               }
+
+               if (tty->icanon && !L_EXTPROC(tty)) {
+                       /* N.B. avoid overrun if nr == 0 */
+                       while (nr && tty->read_cnt) {
+                               int eol;
+
+                               eol = test_and_clear_bit(tty->read_tail,
+                                               tty->read_flags);
+                               c = tty->read_buf[tty->read_tail];
+                               spin_lock_irqsave(&tty->read_lock, flags);
+                               tty->read_tail = ((tty->read_tail+1) &
+                                                 (N_TTY_BUF_SIZE-1));
+                               tty->read_cnt--;
+                               if (eol) {
+                                       /* this test should be redundant:
+                                        * we shouldn't be reading data if
+                                        * canon_data is 0
+                                        */
+                                       if (--tty->canon_data < 0)
+                                               tty->canon_data = 0;
+                               }
+                               spin_unlock_irqrestore(&tty->read_lock, flags);
+
+                               if (!eol || (c != __DISABLED_CHAR)) {
+                                       if (tty_put_user(tty, c, b++)) {
+                                               retval = -EFAULT;
+                                               b--;
+                                               break;
+                                       }
+                                       nr--;
+                               }
+                               if (eol) {
+                                       tty_audit_push(tty);
+                                       break;
+                               }
+                       }
+                       if (retval)
+                               break;
+               } else {
+                       int uncopied;
+                       /* The copy function takes the read lock and handles
+                          locking internally for this case */
+                       uncopied = copy_from_read_buf(tty, &b, &nr);
+                       uncopied += copy_from_read_buf(tty, &b, &nr);
+                       if (uncopied) {
+                               retval = -EFAULT;
+                               break;
+                       }
+               }
+
+               /* If there is enough space in the read buffer now, let the
+                * low-level driver know. We use n_tty_chars_in_buffer() to
+                * check the buffer, as it now knows about canonical mode.
+                * Otherwise, if the driver is throttled and the line is
+                * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
+                * we won't get any more characters.
+                */
+               if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
+                       n_tty_set_room(tty);
+                       check_unthrottle(tty);
+               }
+
+               if (b - buf >= minimum)
+                       break;
+               if (time)
+                       timeout = time;
+       }
+       mutex_unlock(&tty->atomic_read_lock);
+       remove_wait_queue(&tty->read_wait, &wait);
+
+       if (!waitqueue_active(&tty->read_wait))
+               tty->minimum_to_wake = minimum;
+
+       __set_current_state(TASK_RUNNING);
+       size = b - buf;
+       if (size) {
+               retval = size;
+               if (nr)
+                       clear_bit(TTY_PUSH, &tty->flags);
+       } else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
+                goto do_it_again;
+
+       n_tty_set_room(tty);
+       return retval;
+}
+
+/**
+ *     n_tty_write             -       write function for tty
+ *     @tty: tty device
+ *     @file: file object
+ *     @buf: userspace buffer pointer
+ *     @nr: size of I/O
+ *
+ *     Write function of the terminal device.  This is serialized with
+ *     respect to other write callers but not to termios changes, reads
+ *     and other such events.  Since the receive code will echo characters,
+ *     thus calling driver write methods, the output_lock is used in
+ *     the output processing functions called here as well as in the
+ *     echo processing function to protect the column state and space
+ *     left in the buffer.
+ *
+ *     This code must be sure never to sleep through a hangup.
+ *
+ *     Locking: output_lock to protect column state and space left
+ *              (note that the process_output*() functions take this
+ *               lock themselves)
+ */
+
+static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
+                          const unsigned char *buf, size_t nr)
+{
+       const unsigned char *b = buf;
+       DECLARE_WAITQUEUE(wait, current);
+       int c;
+       ssize_t retval = 0;
+
+       /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
+       if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
+               retval = tty_check_change(tty);
+               if (retval)
+                       return retval;
+       }
+
+       /* Write out any echoed characters that are still pending */
+       process_echoes(tty);
+
+       add_wait_queue(&tty->write_wait, &wait);
+       while (1) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+               if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
+                       retval = -EIO;
+                       break;
+               }
+               if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
+                       while (nr > 0) {
+                               ssize_t num = process_output_block(tty, b, nr);
+                               if (num < 0) {
+                                       if (num == -EAGAIN)
+                                               break;
+                                       retval = num;
+                                       goto break_out;
+                               }
+                               b += num;
+                               nr -= num;
+                               if (nr == 0)
+                                       break;
+                               c = *b;
+                               if (process_output(c, tty) < 0)
+                                       break;
+                               b++; nr--;
+                       }
+                       if (tty->ops->flush_chars)
+                               tty->ops->flush_chars(tty);
+               } else {
+                       while (nr > 0) {
+                               c = tty->ops->write(tty, b, nr);
+                               if (c < 0) {
+                                       retval = c;
+                                       goto break_out;
+                               }
+                               if (!c)
+                                       break;
+                               b += c;
+                               nr -= c;
+                       }
+               }
+               if (!nr)
+                       break;
+               if (file->f_flags & O_NONBLOCK) {
+                       retval = -EAGAIN;
+                       break;
+               }
+               schedule();
+       }
+break_out:
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&tty->write_wait, &wait);
+       if (b - buf != nr && tty->fasync)
+               set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       return (b - buf) ? b - buf : retval;
+}
+
+/**
+ *     n_tty_poll              -       poll method for N_TTY
+ *     @tty: terminal device
+ *     @file: file accessing it
+ *     @wait: poll table
+ *
+ *     Called when the line discipline is asked to poll() for data or
+ *     for special events. This code is not serialized with respect to
+ *     other events save open/close.
+ *
+ *     This code must be sure never to sleep through a hangup.
+ *     Called without the kernel lock held - fine
+ */
+
+static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
+                                                       poll_table *wait)
+{
+       unsigned int mask = 0;
+
+       poll_wait(file, &tty->read_wait, wait);
+       poll_wait(file, &tty->write_wait, wait);
+       if (input_available_p(tty, TIME_CHAR(tty) ? 0 : MIN_CHAR(tty)))
+               mask |= POLLIN | POLLRDNORM;
+       if (tty->packet && tty->link->ctrl_status)
+               mask |= POLLPRI | POLLIN | POLLRDNORM;
+       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+               mask |= POLLHUP;
+       if (tty_hung_up_p(file))
+               mask |= POLLHUP;
+       if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
+               if (MIN_CHAR(tty) && !TIME_CHAR(tty))
+                       tty->minimum_to_wake = MIN_CHAR(tty);
+               else
+                       tty->minimum_to_wake = 1;
+       }
+       if (tty->ops->write && !tty_is_writelocked(tty) &&
+                       tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
+                       tty_write_room(tty) > 0)
+               mask |= POLLOUT | POLLWRNORM;
+       return mask;
+}
+
+static unsigned long inq_canon(struct tty_struct *tty)
+{
+       int nr, head, tail;
+
+       if (!tty->canon_data)
+               return 0;
+       head = tty->canon_head;
+       tail = tty->read_tail;
+       nr = (head - tail) & (N_TTY_BUF_SIZE-1);
+       /* Skip EOF-chars.. */
+       while (head != tail) {
+               if (test_bit(tail, tty->read_flags) &&
+                   tty->read_buf[tail] == __DISABLED_CHAR)
+                       nr--;
+               tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+       }
+       return nr;
+}
+
+static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       int retval;
+
+       switch (cmd) {
+       case TIOCOUTQ:
+               return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
+       case TIOCINQ:
+               /* FIXME: Locking */
+               retval = tty->read_cnt;
+               if (L_ICANON(tty))
+                       retval = inq_canon(tty);
+               return put_user(retval, (unsigned int __user *) arg);
+       default:
+               return n_tty_ioctl_helper(tty, file, cmd, arg);
+       }
+}
+
+struct tty_ldisc_ops tty_ldisc_N_TTY = {
+       .magic           = TTY_LDISC_MAGIC,
+       .name            = "n_tty",
+       .open            = n_tty_open,
+       .close           = n_tty_close,
+       .flush_buffer    = n_tty_flush_buffer,
+       .chars_in_buffer = n_tty_chars_in_buffer,
+       .read            = n_tty_read,
+       .write           = n_tty_write,
+       .ioctl           = n_tty_ioctl,
+       .set_termios     = n_tty_set_termios,
+       .poll            = n_tty_poll,
+       .receive_buf     = n_tty_receive_buf,
+       .write_wakeup    = n_tty_write_wakeup
+};
+
+/**
+ *     n_tty_inherit_ops       -       inherit N_TTY methods
+ *     @ops: struct tty_ldisc_ops where to save N_TTY methods
+ *
+ *     Used by a generic struct tty_ldisc_ops to easily inherit N_TTY
+ *     methods.
+ */
+
+void n_tty_inherit_ops(struct tty_ldisc_ops *ops)
+{
+       *ops = tty_ldisc_N_TTY;
+       ops->owner = NULL;
+       ops->refcount = ops->flags = 0;
+}
+EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
new file mode 100644 (file)
index 0000000..923a485
--- /dev/null
@@ -0,0 +1,777 @@
+/*
+ *  linux/drivers/char/pty.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Added support for a Unix98-style ptmx device.
+ *    -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
+ *
+ *  When reading this code see also fs/devpts. In particular note that the
+ *  driver_data field is used by the devpts side as a binding to the devpts
+ *  inode.
+ */
+
+#include <linux/module.h>
+
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/sysctl.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <linux/bitops.h>
+#include <linux/devpts_fs.h>
+#include <linux/slab.h>
+
+#include <asm/system.h>
+
+#ifdef CONFIG_UNIX98_PTYS
+static struct tty_driver *ptm_driver;
+static struct tty_driver *pts_driver;
+#endif
+
+static void pty_close(struct tty_struct *tty, struct file *filp)
+{
+       BUG_ON(!tty);
+       if (tty->driver->subtype == PTY_TYPE_MASTER)
+               WARN_ON(tty->count > 1);
+       else {
+               if (tty->count > 2)
+                       return;
+       }
+       wake_up_interruptible(&tty->read_wait);
+       wake_up_interruptible(&tty->write_wait);
+       tty->packet = 0;
+       if (!tty->link)
+               return;
+       tty->link->packet = 0;
+       set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
+       wake_up_interruptible(&tty->link->read_wait);
+       wake_up_interruptible(&tty->link->write_wait);
+       if (tty->driver->subtype == PTY_TYPE_MASTER) {
+               set_bit(TTY_OTHER_CLOSED, &tty->flags);
+#ifdef CONFIG_UNIX98_PTYS
+               if (tty->driver == ptm_driver)
+                       devpts_pty_kill(tty->link);
+#endif
+               tty_unlock();
+               tty_vhangup(tty->link);
+               tty_lock();
+       }
+}
+
+/*
+ * The unthrottle routine is called by the line discipline to signal
+ * that it can receive more characters.  For PTY's, the TTY_THROTTLED
+ * flag is always set, to force the line discipline to always call the
+ * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
+ * characters in the queue.  This is necessary since each time this
+ * happens, we need to wake up any sleeping processes that could be
+ * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
+ * for the pty buffer to be drained.
+ */
+static void pty_unthrottle(struct tty_struct *tty)
+{
+       tty_wakeup(tty->link);
+       set_bit(TTY_THROTTLED, &tty->flags);
+}
+
+/**
+ *     pty_space       -       report space left for writing
+ *     @to: tty we are writing into
+ *
+ *     The tty buffers allow 64K but we sneak a peak and clip at 8K this
+ *     allows a lot of overspill room for echo and other fun messes to
+ *     be handled properly
+ */
+
+static int pty_space(struct tty_struct *to)
+{
+       int n = 8192 - to->buf.memory_used;
+       if (n < 0)
+               return 0;
+       return n;
+}
+
+/**
+ *     pty_write               -       write to a pty
+ *     @tty: the tty we write from
+ *     @buf: kernel buffer of data
+ *     @count: bytes to write
+ *
+ *     Our "hardware" write method. Data is coming from the ldisc which
+ *     may be in a non sleeping state. We simply throw this at the other
+ *     end of the link as if we were an IRQ handler receiving stuff for
+ *     the other side of the pty/tty pair.
+ */
+
+static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
+{
+       struct tty_struct *to = tty->link;
+
+       if (tty->stopped)
+               return 0;
+
+       if (c > 0) {
+               /* Stuff the data into the input queue of the other end */
+               c = tty_insert_flip_string(to, buf, c);
+               /* And shovel */
+               if (c) {
+                       tty_flip_buffer_push(to);
+                       tty_wakeup(tty);
+               }
+       }
+       return c;
+}
+
+/**
+ *     pty_write_room  -       write space
+ *     @tty: tty we are writing from
+ *
+ *     Report how many bytes the ldisc can send into the queue for
+ *     the other device.
+ */
+
+static int pty_write_room(struct tty_struct *tty)
+{
+       if (tty->stopped)
+               return 0;
+       return pty_space(tty->link);
+}
+
+/**
+ *     pty_chars_in_buffer     -       characters currently in our tx queue
+ *     @tty: our tty
+ *
+ *     Report how much we have in the transmit queue. As everything is
+ *     instantly at the other end this is easy to implement.
+ */
+
+static int pty_chars_in_buffer(struct tty_struct *tty)
+{
+       return 0;
+}
+
+/* Set the lock flag on a pty */
+static int pty_set_lock(struct tty_struct *tty, int __user *arg)
+{
+       int val;
+       if (get_user(val, arg))
+               return -EFAULT;
+       if (val)
+               set_bit(TTY_PTY_LOCK, &tty->flags);
+       else
+               clear_bit(TTY_PTY_LOCK, &tty->flags);
+       return 0;
+}
+
+/* Send a signal to the slave */
+static int pty_signal(struct tty_struct *tty, int sig)
+{
+       unsigned long flags;
+       struct pid *pgrp;
+
+       if (tty->link) {
+               spin_lock_irqsave(&tty->link->ctrl_lock, flags);
+               pgrp = get_pid(tty->link->pgrp);
+               spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
+
+               kill_pgrp(pgrp, sig, 1);
+               put_pid(pgrp);
+       }
+       return 0;
+}
+
+static void pty_flush_buffer(struct tty_struct *tty)
+{
+       struct tty_struct *to = tty->link;
+       unsigned long flags;
+
+       if (!to)
+               return;
+       /* tty_buffer_flush(to); FIXME */
+       if (to->packet) {
+               spin_lock_irqsave(&tty->ctrl_lock, flags);
+               tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
+               wake_up_interruptible(&to->read_wait);
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       }
+}
+
+static int pty_open(struct tty_struct *tty, struct file *filp)
+{
+       int     retval = -ENODEV;
+
+       if (!tty || !tty->link)
+               goto out;
+
+       retval = -EIO;
+       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+               goto out;
+       if (test_bit(TTY_PTY_LOCK, &tty->link->flags))
+               goto out;
+       if (tty->link->count != 1)
+               goto out;
+
+       clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
+       set_bit(TTY_THROTTLED, &tty->flags);
+       retval = 0;
+out:
+       return retval;
+}
+
+static void pty_set_termios(struct tty_struct *tty,
+                                       struct ktermios *old_termios)
+{
+       tty->termios->c_cflag &= ~(CSIZE | PARENB);
+       tty->termios->c_cflag |= (CS8 | CREAD);
+}
+
+/**
+ *     pty_do_resize           -       resize event
+ *     @tty: tty being resized
+ *     @ws: window size being set.
+ *
+ *     Update the termios variables and send the necessary signals to
+ *     peform a terminal resize correctly
+ */
+
+int pty_resize(struct tty_struct *tty,  struct winsize *ws)
+{
+       struct pid *pgrp, *rpgrp;
+       unsigned long flags;
+       struct tty_struct *pty = tty->link;
+
+       /* For a PTY we need to lock the tty side */
+       mutex_lock(&tty->termios_mutex);
+       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
+               goto done;
+
+       /* Get the PID values and reference them so we can
+          avoid holding the tty ctrl lock while sending signals.
+          We need to lock these individually however. */
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       pgrp = get_pid(tty->pgrp);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+       spin_lock_irqsave(&pty->ctrl_lock, flags);
+       rpgrp = get_pid(pty->pgrp);
+       spin_unlock_irqrestore(&pty->ctrl_lock, flags);
+
+       if (pgrp)
+               kill_pgrp(pgrp, SIGWINCH, 1);
+       if (rpgrp != pgrp && rpgrp)
+               kill_pgrp(rpgrp, SIGWINCH, 1);
+
+       put_pid(pgrp);
+       put_pid(rpgrp);
+
+       tty->winsize = *ws;
+       pty->winsize = *ws;     /* Never used so will go away soon */
+done:
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+
+/* Traditional BSD devices */
+#ifdef CONFIG_LEGACY_PTYS
+
+static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+       struct tty_struct *o_tty;
+       int idx = tty->index;
+       int retval;
+
+       o_tty = alloc_tty_struct();
+       if (!o_tty)
+               return -ENOMEM;
+       if (!try_module_get(driver->other->owner)) {
+               /* This cannot in fact currently happen */
+               free_tty_struct(o_tty);
+               return -ENOMEM;
+       }
+       initialize_tty_struct(o_tty, driver->other, idx);
+
+       /* We always use new tty termios data so we can do this
+          the easy way .. */
+       retval = tty_init_termios(tty);
+       if (retval)
+               goto free_mem_out;
+
+       retval = tty_init_termios(o_tty);
+       if (retval) {
+               tty_free_termios(tty);
+               goto free_mem_out;
+       }
+
+       /*
+        * Everything allocated ... set up the o_tty structure.
+        */
+       driver->other->ttys[idx] = o_tty;
+       tty_driver_kref_get(driver->other);
+       if (driver->subtype == PTY_TYPE_MASTER)
+               o_tty->count++;
+       /* Establish the links in both directions */
+       tty->link   = o_tty;
+       o_tty->link = tty;
+
+       tty_driver_kref_get(driver);
+       tty->count++;
+       driver->ttys[idx] = tty;
+       return 0;
+free_mem_out:
+       module_put(o_tty->driver->owner);
+       free_tty_struct(o_tty);
+       return -ENOMEM;
+}
+
+static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
+               return pty_set_lock(tty, (int __user *) arg);
+       case TIOCSIG:    /* Send signal to other side of pty */
+               return pty_signal(tty, (int) arg);
+       }
+       return -ENOIOCTLCMD;
+}
+
+static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
+module_param(legacy_count, int, 0);
+
+/*
+ * The master side of a pty can do TIOCSPTLCK and thus
+ * has pty_bsd_ioctl.
+ */
+static const struct tty_operations master_pty_ops_bsd = {
+       .install = pty_install,
+       .open = pty_open,
+       .close = pty_close,
+       .write = pty_write,
+       .write_room = pty_write_room,
+       .flush_buffer = pty_flush_buffer,
+       .chars_in_buffer = pty_chars_in_buffer,
+       .unthrottle = pty_unthrottle,
+       .set_termios = pty_set_termios,
+       .ioctl = pty_bsd_ioctl,
+       .resize = pty_resize
+};
+
+static const struct tty_operations slave_pty_ops_bsd = {
+       .install = pty_install,
+       .open = pty_open,
+       .close = pty_close,
+       .write = pty_write,
+       .write_room = pty_write_room,
+       .flush_buffer = pty_flush_buffer,
+       .chars_in_buffer = pty_chars_in_buffer,
+       .unthrottle = pty_unthrottle,
+       .set_termios = pty_set_termios,
+       .resize = pty_resize
+};
+
+static void __init legacy_pty_init(void)
+{
+       struct tty_driver *pty_driver, *pty_slave_driver;
+
+       if (legacy_count <= 0)
+               return;
+
+       pty_driver = alloc_tty_driver(legacy_count);
+       if (!pty_driver)
+               panic("Couldn't allocate pty driver");
+
+       pty_slave_driver = alloc_tty_driver(legacy_count);
+       if (!pty_slave_driver)
+               panic("Couldn't allocate pty slave driver");
+
+       pty_driver->owner = THIS_MODULE;
+       pty_driver->driver_name = "pty_master";
+       pty_driver->name = "pty";
+       pty_driver->major = PTY_MASTER_MAJOR;
+       pty_driver->minor_start = 0;
+       pty_driver->type = TTY_DRIVER_TYPE_PTY;
+       pty_driver->subtype = PTY_TYPE_MASTER;
+       pty_driver->init_termios = tty_std_termios;
+       pty_driver->init_termios.c_iflag = 0;
+       pty_driver->init_termios.c_oflag = 0;
+       pty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+       pty_driver->init_termios.c_lflag = 0;
+       pty_driver->init_termios.c_ispeed = 38400;
+       pty_driver->init_termios.c_ospeed = 38400;
+       pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
+       pty_driver->other = pty_slave_driver;
+       tty_set_operations(pty_driver, &master_pty_ops_bsd);
+
+       pty_slave_driver->owner = THIS_MODULE;
+       pty_slave_driver->driver_name = "pty_slave";
+       pty_slave_driver->name = "ttyp";
+       pty_slave_driver->major = PTY_SLAVE_MAJOR;
+       pty_slave_driver->minor_start = 0;
+       pty_slave_driver->type = TTY_DRIVER_TYPE_PTY;
+       pty_slave_driver->subtype = PTY_TYPE_SLAVE;
+       pty_slave_driver->init_termios = tty_std_termios;
+       pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+       pty_slave_driver->init_termios.c_ispeed = 38400;
+       pty_slave_driver->init_termios.c_ospeed = 38400;
+       pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+                                       TTY_DRIVER_REAL_RAW;
+       pty_slave_driver->other = pty_driver;
+       tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);
+
+       if (tty_register_driver(pty_driver))
+               panic("Couldn't register pty driver");
+       if (tty_register_driver(pty_slave_driver))
+               panic("Couldn't register pty slave driver");
+}
+#else
+static inline void legacy_pty_init(void) { }
+#endif
+
+/* Unix98 devices */
+#ifdef CONFIG_UNIX98_PTYS
+/*
+ * sysctl support for setting limits on the number of Unix98 ptys allocated.
+ * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
+ */
+int pty_limit = NR_UNIX98_PTY_DEFAULT;
+static int pty_limit_min;
+static int pty_limit_max = NR_UNIX98_PTY_MAX;
+static int pty_count;
+
+static struct cdev ptmx_cdev;
+
+static struct ctl_table pty_table[] = {
+       {
+               .procname       = "max",
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .data           = &pty_limit,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &pty_limit_min,
+               .extra2         = &pty_limit_max,
+       }, {
+               .procname       = "nr",
+               .maxlen         = sizeof(int),
+               .mode           = 0444,
+               .data           = &pty_count,
+               .proc_handler   = proc_dointvec,
+       }, 
+       {}
+};
+
+static struct ctl_table pty_kern_table[] = {
+       {
+               .procname       = "pty",
+               .mode           = 0555,
+               .child          = pty_table,
+       },
+       {}
+};
+
+static struct ctl_table pty_root_table[] = {
+       {
+               .procname       = "kernel",
+               .mode           = 0555,
+               .child          = pty_kern_table,
+       },
+       {}
+};
+
+
+static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
+                           unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
+               return pty_set_lock(tty, (int __user *)arg);
+       case TIOCGPTN: /* Get PT Number */
+               return put_user(tty->index, (unsigned int __user *)arg);
+       case TIOCSIG:    /* Send signal to other side of pty */
+               return pty_signal(tty, (int) arg);
+       }
+
+       return -ENOIOCTLCMD;
+}
+
+/**
+ *     ptm_unix98_lookup       -       find a pty master
+ *     @driver: ptm driver
+ *     @idx: tty index
+ *
+ *     Look up a pty master device. Called under the tty_mutex for now.
+ *     This provides our locking.
+ */
+
+static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
+               struct inode *ptm_inode, int idx)
+{
+       struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
+       if (tty)
+               tty = tty->link;
+       return tty;
+}
+
+/**
+ *     pts_unix98_lookup       -       find a pty slave
+ *     @driver: pts driver
+ *     @idx: tty index
+ *
+ *     Look up a pty master device. Called under the tty_mutex for now.
+ *     This provides our locking.
+ */
+
+static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
+               struct inode *pts_inode, int idx)
+{
+       struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
+       /* Master must be open before slave */
+       if (!tty)
+               return ERR_PTR(-EIO);
+       return tty;
+}
+
+static void pty_unix98_shutdown(struct tty_struct *tty)
+{
+       /* We have our own method as we don't use the tty index */
+       kfree(tty->termios);
+}
+
+/* We have no need to install and remove our tty objects as devpts does all
+   the work for us */
+
+static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+       struct tty_struct *o_tty;
+       int idx = tty->index;
+
+       o_tty = alloc_tty_struct();
+       if (!o_tty)
+               return -ENOMEM;
+       if (!try_module_get(driver->other->owner)) {
+               /* This cannot in fact currently happen */
+               free_tty_struct(o_tty);
+               return -ENOMEM;
+       }
+       initialize_tty_struct(o_tty, driver->other, idx);
+
+       tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+       if (tty->termios == NULL)
+               goto free_mem_out;
+       *tty->termios = driver->init_termios;
+       tty->termios_locked = tty->termios + 1;
+
+       o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+       if (o_tty->termios == NULL)
+               goto free_mem_out;
+       *o_tty->termios = driver->other->init_termios;
+       o_tty->termios_locked = o_tty->termios + 1;
+
+       tty_driver_kref_get(driver->other);
+       if (driver->subtype == PTY_TYPE_MASTER)
+               o_tty->count++;
+       /* Establish the links in both directions */
+       tty->link   = o_tty;
+       o_tty->link = tty;
+       /*
+        * All structures have been allocated, so now we install them.
+        * Failures after this point use release_tty to clean up, so
+        * there's no need to null out the local pointers.
+        */
+       tty_driver_kref_get(driver);
+       tty->count++;
+       pty_count++;
+       return 0;
+free_mem_out:
+       kfree(o_tty->termios);
+       module_put(o_tty->driver->owner);
+       free_tty_struct(o_tty);
+       kfree(tty->termios);
+       return -ENOMEM;
+}
+
+static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
+{
+       pty_count--;
+}
+
+static const struct tty_operations ptm_unix98_ops = {
+       .lookup = ptm_unix98_lookup,
+       .install = pty_unix98_install,
+       .remove = pty_unix98_remove,
+       .open = pty_open,
+       .close = pty_close,
+       .write = pty_write,
+       .write_room = pty_write_room,
+       .flush_buffer = pty_flush_buffer,
+       .chars_in_buffer = pty_chars_in_buffer,
+       .unthrottle = pty_unthrottle,
+       .set_termios = pty_set_termios,
+       .ioctl = pty_unix98_ioctl,
+       .shutdown = pty_unix98_shutdown,
+       .resize = pty_resize
+};
+
+static const struct tty_operations pty_unix98_ops = {
+       .lookup = pts_unix98_lookup,
+       .install = pty_unix98_install,
+       .remove = pty_unix98_remove,
+       .open = pty_open,
+       .close = pty_close,
+       .write = pty_write,
+       .write_room = pty_write_room,
+       .flush_buffer = pty_flush_buffer,
+       .chars_in_buffer = pty_chars_in_buffer,
+       .unthrottle = pty_unthrottle,
+       .set_termios = pty_set_termios,
+       .shutdown = pty_unix98_shutdown
+};
+
+/**
+ *     ptmx_open               -       open a unix 98 pty master
+ *     @inode: inode of device file
+ *     @filp: file pointer to tty
+ *
+ *     Allocate a unix98 pty master device from the ptmx driver.
+ *
+ *     Locking: tty_mutex protects the init_dev work. tty->count should
+ *             protect the rest.
+ *             allocated_ptys_lock handles the list of free pty numbers
+ */
+
+static int ptmx_open(struct inode *inode, struct file *filp)
+{
+       struct tty_struct *tty;
+       int retval;
+       int index;
+
+       nonseekable_open(inode, filp);
+
+       /* find a device that is not in use. */
+       tty_lock();
+       index = devpts_new_index(inode);
+       tty_unlock();
+       if (index < 0)
+               return index;
+
+       mutex_lock(&tty_mutex);
+       tty_lock();
+       tty = tty_init_dev(ptm_driver, index, 1);
+       mutex_unlock(&tty_mutex);
+
+       if (IS_ERR(tty)) {
+               retval = PTR_ERR(tty);
+               goto out;
+       }
+
+       set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
+
+       retval = tty_add_file(tty, filp);
+       if (retval)
+               goto out;
+
+       retval = devpts_pty_new(inode, tty->link);
+       if (retval)
+               goto out1;
+
+       retval = ptm_driver->ops->open(tty, filp);
+       if (retval)
+               goto out2;
+out1:
+       tty_unlock();
+       return retval;
+out2:
+       tty_unlock();
+       tty_release(inode, filp);
+       return retval;
+out:
+       devpts_kill_index(inode, index);
+       tty_unlock();
+       return retval;
+}
+
+static struct file_operations ptmx_fops;
+
+static void __init unix98_pty_init(void)
+{
+       ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
+       if (!ptm_driver)
+               panic("Couldn't allocate Unix98 ptm driver");
+       pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
+       if (!pts_driver)
+               panic("Couldn't allocate Unix98 pts driver");
+
+       ptm_driver->owner = THIS_MODULE;
+       ptm_driver->driver_name = "pty_master";
+       ptm_driver->name = "ptm";
+       ptm_driver->major = UNIX98_PTY_MASTER_MAJOR;
+       ptm_driver->minor_start = 0;
+       ptm_driver->type = TTY_DRIVER_TYPE_PTY;
+       ptm_driver->subtype = PTY_TYPE_MASTER;
+       ptm_driver->init_termios = tty_std_termios;
+       ptm_driver->init_termios.c_iflag = 0;
+       ptm_driver->init_termios.c_oflag = 0;
+       ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+       ptm_driver->init_termios.c_lflag = 0;
+       ptm_driver->init_termios.c_ispeed = 38400;
+       ptm_driver->init_termios.c_ospeed = 38400;
+       ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
+               TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
+       ptm_driver->other = pts_driver;
+       tty_set_operations(ptm_driver, &ptm_unix98_ops);
+
+       pts_driver->owner = THIS_MODULE;
+       pts_driver->driver_name = "pty_slave";
+       pts_driver->name = "pts";
+       pts_driver->major = UNIX98_PTY_SLAVE_MAJOR;
+       pts_driver->minor_start = 0;
+       pts_driver->type = TTY_DRIVER_TYPE_PTY;
+       pts_driver->subtype = PTY_TYPE_SLAVE;
+       pts_driver->init_termios = tty_std_termios;
+       pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+       pts_driver->init_termios.c_ispeed = 38400;
+       pts_driver->init_termios.c_ospeed = 38400;
+       pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
+               TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
+       pts_driver->other = ptm_driver;
+       tty_set_operations(pts_driver, &pty_unix98_ops);
+
+       if (tty_register_driver(ptm_driver))
+               panic("Couldn't register Unix98 ptm driver");
+       if (tty_register_driver(pts_driver))
+               panic("Couldn't register Unix98 pts driver");
+
+       register_sysctl_table(pty_root_table);
+
+       /* Now create the /dev/ptmx special device */
+       tty_default_fops(&ptmx_fops);
+       ptmx_fops.open = ptmx_open;
+
+       cdev_init(&ptmx_cdev, &ptmx_fops);
+       if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
+           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
+               panic("Couldn't register /dev/ptmx driver\n");
+       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
+}
+
+#else
+static inline void unix98_pty_init(void) { }
+#endif
+
+static int __init pty_init(void)
+{
+       legacy_pty_init();
+       unix98_pty_init();
+       return 0;
+}
+module_init(pty_init);
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
new file mode 100644 (file)
index 0000000..eaa5d3e
--- /dev/null
@@ -0,0 +1,811 @@
+/*
+ *     Linux Magic System Request Key Hacks
+ *
+ *     (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *     based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
+ *
+ *     (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
+ *     overhauled to use key registration
+ *     based upon discusions in irc://irc.openprojects.net/#kernelnewbies
+ *
+ *     Copyright (c) 2010 Dmitry Torokhov
+ *     Input handler conversion
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/reboot.h>
+#include <linux/sysrq.h>
+#include <linux/kbd_kern.h>
+#include <linux/proc_fs.h>
+#include <linux/nmi.h>
+#include <linux/quotaops.h>
+#include <linux/perf_event.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/suspend.h>
+#include <linux/writeback.h>
+#include <linux/buffer_head.h>         /* for fsync_bdev() */
+#include <linux/swap.h>
+#include <linux/spinlock.h>
+#include <linux/vt_kern.h>
+#include <linux/workqueue.h>
+#include <linux/hrtimer.h>
+#include <linux/oom.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+
+#include <asm/ptrace.h>
+#include <asm/irq_regs.h>
+
+/* Whether we react on sysrq keys or just ignore them */
+static int __read_mostly sysrq_enabled = 1;
+static bool __read_mostly sysrq_always_enabled;
+
+static bool sysrq_on(void)
+{
+       return sysrq_enabled || sysrq_always_enabled;
+}
+
+/*
+ * A value of 1 means 'all', other nonzero values are an op mask:
+ */
+static bool sysrq_on_mask(int mask)
+{
+       return sysrq_always_enabled ||
+              sysrq_enabled == 1 ||
+              (sysrq_enabled & mask);
+}
+
+static int __init sysrq_always_enabled_setup(char *str)
+{
+       sysrq_always_enabled = true;
+       pr_info("sysrq always enabled.\n");
+
+       return 1;
+}
+
+__setup("sysrq_always_enabled", sysrq_always_enabled_setup);
+
+
+static void sysrq_handle_loglevel(int key)
+{
+       int i;
+
+       i = key - '0';
+       console_loglevel = 7;
+       printk("Loglevel set to %d\n", i);
+       console_loglevel = i;
+}
+static struct sysrq_key_op sysrq_loglevel_op = {
+       .handler        = sysrq_handle_loglevel,
+       .help_msg       = "loglevel(0-9)",
+       .action_msg     = "Changing Loglevel",
+       .enable_mask    = SYSRQ_ENABLE_LOG,
+};
+
+#ifdef CONFIG_VT
+static void sysrq_handle_SAK(int key)
+{
+       struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
+       schedule_work(SAK_work);
+}
+static struct sysrq_key_op sysrq_SAK_op = {
+       .handler        = sysrq_handle_SAK,
+       .help_msg       = "saK",
+       .action_msg     = "SAK",
+       .enable_mask    = SYSRQ_ENABLE_KEYBOARD,
+};
+#else
+#define sysrq_SAK_op (*(struct sysrq_key_op *)NULL)
+#endif
+
+#ifdef CONFIG_VT
+static void sysrq_handle_unraw(int key)
+{
+       struct kbd_struct *kbd = &kbd_table[fg_console];
+
+       if (kbd)
+               kbd->kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
+}
+static struct sysrq_key_op sysrq_unraw_op = {
+       .handler        = sysrq_handle_unraw,
+       .help_msg       = "unRaw",
+       .action_msg     = "Keyboard mode set to system default",
+       .enable_mask    = SYSRQ_ENABLE_KEYBOARD,
+};
+#else
+#define sysrq_unraw_op (*(struct sysrq_key_op *)NULL)
+#endif /* CONFIG_VT */
+
+static void sysrq_handle_crash(int key)
+{
+       char *killer = NULL;
+
+       panic_on_oops = 1;      /* force panic */
+       wmb();
+       *killer = 1;
+}
+static struct sysrq_key_op sysrq_crash_op = {
+       .handler        = sysrq_handle_crash,
+       .help_msg       = "Crash",
+       .action_msg     = "Trigger a crash",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+
+static void sysrq_handle_reboot(int key)
+{
+       lockdep_off();
+       local_irq_enable();
+       emergency_restart();
+}
+static struct sysrq_key_op sysrq_reboot_op = {
+       .handler        = sysrq_handle_reboot,
+       .help_msg       = "reBoot",
+       .action_msg     = "Resetting",
+       .enable_mask    = SYSRQ_ENABLE_BOOT,
+};
+
+static void sysrq_handle_sync(int key)
+{
+       emergency_sync();
+}
+static struct sysrq_key_op sysrq_sync_op = {
+       .handler        = sysrq_handle_sync,
+       .help_msg       = "Sync",
+       .action_msg     = "Emergency Sync",
+       .enable_mask    = SYSRQ_ENABLE_SYNC,
+};
+
+static void sysrq_handle_show_timers(int key)
+{
+       sysrq_timer_list_show();
+}
+
+static struct sysrq_key_op sysrq_show_timers_op = {
+       .handler        = sysrq_handle_show_timers,
+       .help_msg       = "show-all-timers(Q)",
+       .action_msg     = "Show clockevent devices & pending hrtimers (no others)",
+};
+
+static void sysrq_handle_mountro(int key)
+{
+       emergency_remount();
+}
+static struct sysrq_key_op sysrq_mountro_op = {
+       .handler        = sysrq_handle_mountro,
+       .help_msg       = "Unmount",
+       .action_msg     = "Emergency Remount R/O",
+       .enable_mask    = SYSRQ_ENABLE_REMOUNT,
+};
+
+#ifdef CONFIG_LOCKDEP
+static void sysrq_handle_showlocks(int key)
+{
+       debug_show_all_locks();
+}
+
+static struct sysrq_key_op sysrq_showlocks_op = {
+       .handler        = sysrq_handle_showlocks,
+       .help_msg       = "show-all-locks(D)",
+       .action_msg     = "Show Locks Held",
+};
+#else
+#define sysrq_showlocks_op (*(struct sysrq_key_op *)NULL)
+#endif
+
+#ifdef CONFIG_SMP
+static DEFINE_SPINLOCK(show_lock);
+
+static void showacpu(void *dummy)
+{
+       unsigned long flags;
+
+       /* Idle CPUs have no interesting backtrace. */
+       if (idle_cpu(smp_processor_id()))
+               return;
+
+       spin_lock_irqsave(&show_lock, flags);
+       printk(KERN_INFO "CPU%d:\n", smp_processor_id());
+       show_stack(NULL, NULL);
+       spin_unlock_irqrestore(&show_lock, flags);
+}
+
+static void sysrq_showregs_othercpus(struct work_struct *dummy)
+{
+       smp_call_function(showacpu, NULL, 0);
+}
+
+static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus);
+
+static void sysrq_handle_showallcpus(int key)
+{
+       /*
+        * Fall back to the workqueue based printing if the
+        * backtrace printing did not succeed or the
+        * architecture has no support for it:
+        */
+       if (!trigger_all_cpu_backtrace()) {
+               struct pt_regs *regs = get_irq_regs();
+
+               if (regs) {
+                       printk(KERN_INFO "CPU%d:\n", smp_processor_id());
+                       show_regs(regs);
+               }
+               schedule_work(&sysrq_showallcpus);
+       }
+}
+
+static struct sysrq_key_op sysrq_showallcpus_op = {
+       .handler        = sysrq_handle_showallcpus,
+       .help_msg       = "show-backtrace-all-active-cpus(L)",
+       .action_msg     = "Show backtrace of all active CPUs",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+#endif
+
+static void sysrq_handle_showregs(int key)
+{
+       struct pt_regs *regs = get_irq_regs();
+       if (regs)
+               show_regs(regs);
+       perf_event_print_debug();
+}
+static struct sysrq_key_op sysrq_showregs_op = {
+       .handler        = sysrq_handle_showregs,
+       .help_msg       = "show-registers(P)",
+       .action_msg     = "Show Regs",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+
+static void sysrq_handle_showstate(int key)
+{
+       show_state();
+}
+static struct sysrq_key_op sysrq_showstate_op = {
+       .handler        = sysrq_handle_showstate,
+       .help_msg       = "show-task-states(T)",
+       .action_msg     = "Show State",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+
+static void sysrq_handle_showstate_blocked(int key)
+{
+       show_state_filter(TASK_UNINTERRUPTIBLE);
+}
+static struct sysrq_key_op sysrq_showstate_blocked_op = {
+       .handler        = sysrq_handle_showstate_blocked,
+       .help_msg       = "show-blocked-tasks(W)",
+       .action_msg     = "Show Blocked State",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+
+#ifdef CONFIG_TRACING
+#include <linux/ftrace.h>
+
+static void sysrq_ftrace_dump(int key)
+{
+       ftrace_dump(DUMP_ALL);
+}
+static struct sysrq_key_op sysrq_ftrace_dump_op = {
+       .handler        = sysrq_ftrace_dump,
+       .help_msg       = "dump-ftrace-buffer(Z)",
+       .action_msg     = "Dump ftrace buffer",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+#else
+#define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)NULL)
+#endif
+
+static void sysrq_handle_showmem(int key)
+{
+       show_mem();
+}
+static struct sysrq_key_op sysrq_showmem_op = {
+       .handler        = sysrq_handle_showmem,
+       .help_msg       = "show-memory-usage(M)",
+       .action_msg     = "Show Memory",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+
+/*
+ * Signal sysrq helper function.  Sends a signal to all user processes.
+ */
+static void send_sig_all(int sig)
+{
+       struct task_struct *p;
+
+       for_each_process(p) {
+               if (p->mm && !is_global_init(p))
+                       /* Not swapper, init nor kernel thread */
+                       force_sig(sig, p);
+       }
+}
+
+static void sysrq_handle_term(int key)
+{
+       send_sig_all(SIGTERM);
+       console_loglevel = 8;
+}
+static struct sysrq_key_op sysrq_term_op = {
+       .handler        = sysrq_handle_term,
+       .help_msg       = "terminate-all-tasks(E)",
+       .action_msg     = "Terminate All Tasks",
+       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
+};
+
+static void moom_callback(struct work_struct *ignored)
+{
+       out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0, NULL);
+}
+
+static DECLARE_WORK(moom_work, moom_callback);
+
+static void sysrq_handle_moom(int key)
+{
+       schedule_work(&moom_work);
+}
+static struct sysrq_key_op sysrq_moom_op = {
+       .handler        = sysrq_handle_moom,
+       .help_msg       = "memory-full-oom-kill(F)",
+       .action_msg     = "Manual OOM execution",
+       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
+};
+
+#ifdef CONFIG_BLOCK
+static void sysrq_handle_thaw(int key)
+{
+       emergency_thaw_all();
+}
+static struct sysrq_key_op sysrq_thaw_op = {
+       .handler        = sysrq_handle_thaw,
+       .help_msg       = "thaw-filesystems(J)",
+       .action_msg     = "Emergency Thaw of all frozen filesystems",
+       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
+};
+#endif
+
+static void sysrq_handle_kill(int key)
+{
+       send_sig_all(SIGKILL);
+       console_loglevel = 8;
+}
+static struct sysrq_key_op sysrq_kill_op = {
+       .handler        = sysrq_handle_kill,
+       .help_msg       = "kill-all-tasks(I)",
+       .action_msg     = "Kill All Tasks",
+       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
+};
+
+static void sysrq_handle_unrt(int key)
+{
+       normalize_rt_tasks();
+}
+static struct sysrq_key_op sysrq_unrt_op = {
+       .handler        = sysrq_handle_unrt,
+       .help_msg       = "nice-all-RT-tasks(N)",
+       .action_msg     = "Nice All RT Tasks",
+       .enable_mask    = SYSRQ_ENABLE_RTNICE,
+};
+
+/* Key Operations table and lock */
+static DEFINE_SPINLOCK(sysrq_key_table_lock);
+
+static struct sysrq_key_op *sysrq_key_table[36] = {
+       &sysrq_loglevel_op,             /* 0 */
+       &sysrq_loglevel_op,             /* 1 */
+       &sysrq_loglevel_op,             /* 2 */
+       &sysrq_loglevel_op,             /* 3 */
+       &sysrq_loglevel_op,             /* 4 */
+       &sysrq_loglevel_op,             /* 5 */
+       &sysrq_loglevel_op,             /* 6 */
+       &sysrq_loglevel_op,             /* 7 */
+       &sysrq_loglevel_op,             /* 8 */
+       &sysrq_loglevel_op,             /* 9 */
+
+       /*
+        * a: Don't use for system provided sysrqs, it is handled specially on
+        * sparc and will never arrive.
+        */
+       NULL,                           /* a */
+       &sysrq_reboot_op,               /* b */
+       &sysrq_crash_op,                /* c & ibm_emac driver debug */
+       &sysrq_showlocks_op,            /* d */
+       &sysrq_term_op,                 /* e */
+       &sysrq_moom_op,                 /* f */
+       /* g: May be registered for the kernel debugger */
+       NULL,                           /* g */
+       NULL,                           /* h - reserved for help */
+       &sysrq_kill_op,                 /* i */
+#ifdef CONFIG_BLOCK
+       &sysrq_thaw_op,                 /* j */
+#else
+       NULL,                           /* j */
+#endif
+       &sysrq_SAK_op,                  /* k */
+#ifdef CONFIG_SMP
+       &sysrq_showallcpus_op,          /* l */
+#else
+       NULL,                           /* l */
+#endif
+       &sysrq_showmem_op,              /* m */
+       &sysrq_unrt_op,                 /* n */
+       /* o: This will often be registered as 'Off' at init time */
+       NULL,                           /* o */
+       &sysrq_showregs_op,             /* p */
+       &sysrq_show_timers_op,          /* q */
+       &sysrq_unraw_op,                /* r */
+       &sysrq_sync_op,                 /* s */
+       &sysrq_showstate_op,            /* t */
+       &sysrq_mountro_op,              /* u */
+       /* v: May be registered for frame buffer console restore */
+       NULL,                           /* v */
+       &sysrq_showstate_blocked_op,    /* w */
+       /* x: May be registered on ppc/powerpc for xmon */
+       NULL,                           /* x */
+       /* y: May be registered on sparc64 for global register dump */
+       NULL,                           /* y */
+       &sysrq_ftrace_dump_op,          /* z */
+};
+
+/* key2index calculation, -1 on invalid index */
+static int sysrq_key_table_key2index(int key)
+{
+       int retval;
+
+       if ((key >= '0') && (key <= '9'))
+               retval = key - '0';
+       else if ((key >= 'a') && (key <= 'z'))
+               retval = key + 10 - 'a';
+       else
+               retval = -1;
+       return retval;
+}
+
+/*
+ * get and put functions for the table, exposed to modules.
+ */
+struct sysrq_key_op *__sysrq_get_key_op(int key)
+{
+        struct sysrq_key_op *op_p = NULL;
+        int i;
+
+       i = sysrq_key_table_key2index(key);
+       if (i != -1)
+               op_p = sysrq_key_table[i];
+
+        return op_p;
+}
+
+static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p)
+{
+        int i = sysrq_key_table_key2index(key);
+
+        if (i != -1)
+                sysrq_key_table[i] = op_p;
+}
+
+void __handle_sysrq(int key, bool check_mask)
+{
+       struct sysrq_key_op *op_p;
+       int orig_log_level;
+       int i;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sysrq_key_table_lock, flags);
+       /*
+        * Raise the apparent loglevel to maximum so that the sysrq header
+        * is shown to provide the user with positive feedback.  We do not
+        * simply emit this at KERN_EMERG as that would change message
+        * routing in the consumers of /proc/kmsg.
+        */
+       orig_log_level = console_loglevel;
+       console_loglevel = 7;
+       printk(KERN_INFO "SysRq : ");
+
+        op_p = __sysrq_get_key_op(key);
+        if (op_p) {
+               /*
+                * Should we check for enabled operations (/proc/sysrq-trigger
+                * should not) and is the invoked operation enabled?
+                */
+               if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
+                       printk("%s\n", op_p->action_msg);
+                       console_loglevel = orig_log_level;
+                       op_p->handler(key);
+               } else {
+                       printk("This sysrq operation is disabled.\n");
+               }
+       } else {
+               printk("HELP : ");
+               /* Only print the help msg once per handler */
+               for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) {
+                       if (sysrq_key_table[i]) {
+                               int j;
+
+                               for (j = 0; sysrq_key_table[i] !=
+                                               sysrq_key_table[j]; j++)
+                                       ;
+                               if (j != i)
+                                       continue;
+                               printk("%s ", sysrq_key_table[i]->help_msg);
+                       }
+               }
+               printk("\n");
+               console_loglevel = orig_log_level;
+       }
+       spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
+}
+
+void handle_sysrq(int key)
+{
+       if (sysrq_on())
+               __handle_sysrq(key, true);
+}
+EXPORT_SYMBOL(handle_sysrq);
+
+#ifdef CONFIG_INPUT
+
+/* Simple translation table for the SysRq keys */
+static const unsigned char sysrq_xlate[KEY_MAX + 1] =
+        "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
+        "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
+        "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
+        "bnm,./\000*\000 \000\201\202\203\204\205"      /* 0x30 - 0x3f */
+        "\206\207\210\211\212\000\000789-456+1"         /* 0x40 - 0x4f */
+        "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+        "\r\000/";                                      /* 0x60 - 0x6f */
+
+static bool sysrq_down;
+static int sysrq_alt_use;
+static int sysrq_alt;
+static DEFINE_SPINLOCK(sysrq_event_lock);
+
+static bool sysrq_filter(struct input_handle *handle, unsigned int type,
+                        unsigned int code, int value)
+{
+       bool suppress;
+
+       /* We are called with interrupts disabled, just take the lock */
+       spin_lock(&sysrq_event_lock);
+
+       if (type != EV_KEY)
+               goto out;
+
+       switch (code) {
+
+       case KEY_LEFTALT:
+       case KEY_RIGHTALT:
+               if (value)
+                       sysrq_alt = code;
+               else {
+                       if (sysrq_down && code == sysrq_alt_use)
+                               sysrq_down = false;
+
+                       sysrq_alt = 0;
+               }
+               break;
+
+       case KEY_SYSRQ:
+               if (value == 1 && sysrq_alt) {
+                       sysrq_down = true;
+                       sysrq_alt_use = sysrq_alt;
+               }
+               break;
+
+       default:
+               if (sysrq_down && value && value != 2)
+                       __handle_sysrq(sysrq_xlate[code], true);
+               break;
+       }
+
+out:
+       suppress = sysrq_down;
+       spin_unlock(&sysrq_event_lock);
+
+       return suppress;
+}
+
+static int sysrq_connect(struct input_handler *handler,
+                        struct input_dev *dev,
+                        const struct input_device_id *id)
+{
+       struct input_handle *handle;
+       int error;
+
+       sysrq_down = false;
+       sysrq_alt = 0;
+
+       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+       if (!handle)
+               return -ENOMEM;
+
+       handle->dev = dev;
+       handle->handler = handler;
+       handle->name = "sysrq";
+
+       error = input_register_handle(handle);
+       if (error) {
+               pr_err("Failed to register input sysrq handler, error %d\n",
+                       error);
+               goto err_free;
+       }
+
+       error = input_open_device(handle);
+       if (error) {
+               pr_err("Failed to open input device, error %d\n", error);
+               goto err_unregister;
+       }
+
+       return 0;
+
+ err_unregister:
+       input_unregister_handle(handle);
+ err_free:
+       kfree(handle);
+       return error;
+}
+
+static void sysrq_disconnect(struct input_handle *handle)
+{
+       input_close_device(handle);
+       input_unregister_handle(handle);
+       kfree(handle);
+}
+
+/*
+ * We are matching on KEY_LEFTALT instead of KEY_SYSRQ because not all
+ * keyboards have SysRq key predefined and so user may add it to keymap
+ * later, but we expect all such keyboards to have left alt.
+ */
+static const struct input_device_id sysrq_ids[] = {
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+                               INPUT_DEVICE_ID_MATCH_KEYBIT,
+               .evbit = { BIT_MASK(EV_KEY) },
+               .keybit = { BIT_MASK(KEY_LEFTALT) },
+       },
+       { },
+};
+
+static struct input_handler sysrq_handler = {
+       .filter         = sysrq_filter,
+       .connect        = sysrq_connect,
+       .disconnect     = sysrq_disconnect,
+       .name           = "sysrq",
+       .id_table       = sysrq_ids,
+};
+
+static bool sysrq_handler_registered;
+
+static inline void sysrq_register_handler(void)
+{
+       int error;
+
+       error = input_register_handler(&sysrq_handler);
+       if (error)
+               pr_err("Failed to register input handler, error %d", error);
+       else
+               sysrq_handler_registered = true;
+}
+
+static inline void sysrq_unregister_handler(void)
+{
+       if (sysrq_handler_registered) {
+               input_unregister_handler(&sysrq_handler);
+               sysrq_handler_registered = false;
+       }
+}
+
+#else
+
+static inline void sysrq_register_handler(void)
+{
+}
+
+static inline void sysrq_unregister_handler(void)
+{
+}
+
+#endif /* CONFIG_INPUT */
+
+int sysrq_toggle_support(int enable_mask)
+{
+       bool was_enabled = sysrq_on();
+
+       sysrq_enabled = enable_mask;
+
+       if (was_enabled != sysrq_on()) {
+               if (sysrq_on())
+                       sysrq_register_handler();
+               else
+                       sysrq_unregister_handler();
+       }
+
+       return 0;
+}
+
+static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
+                                struct sysrq_key_op *remove_op_p)
+{
+       int retval;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sysrq_key_table_lock, flags);
+       if (__sysrq_get_key_op(key) == remove_op_p) {
+               __sysrq_put_key_op(key, insert_op_p);
+               retval = 0;
+       } else {
+               retval = -1;
+       }
+       spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
+       return retval;
+}
+
+int register_sysrq_key(int key, struct sysrq_key_op *op_p)
+{
+       return __sysrq_swap_key_ops(key, op_p, NULL);
+}
+EXPORT_SYMBOL(register_sysrq_key);
+
+int unregister_sysrq_key(int key, struct sysrq_key_op *op_p)
+{
+       return __sysrq_swap_key_ops(key, NULL, op_p);
+}
+EXPORT_SYMBOL(unregister_sysrq_key);
+
+#ifdef CONFIG_PROC_FS
+/*
+ * writing 'C' to /proc/sysrq-trigger is like sysrq-C
+ */
+static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
+                                  size_t count, loff_t *ppos)
+{
+       if (count) {
+               char c;
+
+               if (get_user(c, buf))
+                       return -EFAULT;
+               __handle_sysrq(c, false);
+       }
+
+       return count;
+}
+
+static const struct file_operations proc_sysrq_trigger_operations = {
+       .write          = write_sysrq_trigger,
+       .llseek         = noop_llseek,
+};
+
+static void sysrq_init_procfs(void)
+{
+       if (!proc_create("sysrq-trigger", S_IWUSR, NULL,
+                        &proc_sysrq_trigger_operations))
+               pr_err("Failed to register proc interface\n");
+}
+
+#else
+
+static inline void sysrq_init_procfs(void)
+{
+}
+
+#endif /* CONFIG_PROC_FS */
+
+static int __init sysrq_init(void)
+{
+       sysrq_init_procfs();
+
+       if (sysrq_on())
+               sysrq_register_handler();
+
+       return 0;
+}
+module_init(sysrq_init);
diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c
new file mode 100644 (file)
index 0000000..f64582b
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * Creating audit events from TTY input.
+ *
+ * Copyright (C) 2007 Red Hat, Inc.  All rights reserved.  This copyrighted
+ * material is made available to anyone wishing to use, modify, copy, or
+ * redistribute it subject to the terms and conditions of the GNU General
+ * Public License v.2.
+ *
+ * Authors: Miloslav Trmac <mitr@redhat.com>
+ */
+
+#include <linux/audit.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+
+struct tty_audit_buf {
+       atomic_t count;
+       struct mutex mutex;     /* Protects all data below */
+       int major, minor;       /* The TTY which the data is from */
+       unsigned icanon:1;
+       size_t valid;
+       unsigned char *data;    /* Allocated size N_TTY_BUF_SIZE */
+};
+
+static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
+                                                int icanon)
+{
+       struct tty_audit_buf *buf;
+
+       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+       if (!buf)
+               goto err;
+       buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+       if (!buf->data)
+               goto err_buf;
+       atomic_set(&buf->count, 1);
+       mutex_init(&buf->mutex);
+       buf->major = major;
+       buf->minor = minor;
+       buf->icanon = icanon;
+       buf->valid = 0;
+       return buf;
+
+err_buf:
+       kfree(buf);
+err:
+       return NULL;
+}
+
+static void tty_audit_buf_free(struct tty_audit_buf *buf)
+{
+       WARN_ON(buf->valid != 0);
+       kfree(buf->data);
+       kfree(buf);
+}
+
+static void tty_audit_buf_put(struct tty_audit_buf *buf)
+{
+       if (atomic_dec_and_test(&buf->count))
+               tty_audit_buf_free(buf);
+}
+
+static void tty_audit_log(const char *description, struct task_struct *tsk,
+                         uid_t loginuid, unsigned sessionid, int major,
+                         int minor, unsigned char *data, size_t size)
+{
+       struct audit_buffer *ab;
+
+       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
+       if (ab) {
+               char name[sizeof(tsk->comm)];
+               uid_t uid = task_uid(tsk);
+
+               audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u "
+                                "major=%d minor=%d comm=", description,
+                                tsk->pid, uid, loginuid, sessionid,
+                                major, minor);
+               get_task_comm(name, tsk);
+               audit_log_untrustedstring(ab, name);
+               audit_log_format(ab, " data=");
+               audit_log_n_hex(ab, data, size);
+               audit_log_end(ab);
+       }
+}
+
+/**
+ *     tty_audit_buf_push      -       Push buffered data out
+ *
+ *     Generate an audit message from the contents of @buf, which is owned by
+ *     @tsk with @loginuid.  @buf->mutex must be locked.
+ */
+static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
+                              unsigned int sessionid,
+                              struct tty_audit_buf *buf)
+{
+       if (buf->valid == 0)
+               return;
+       if (audit_enabled == 0)
+               return;
+       tty_audit_log("tty", tsk, loginuid, sessionid, buf->major, buf->minor,
+                     buf->data, buf->valid);
+       buf->valid = 0;
+}
+
+/**
+ *     tty_audit_buf_push_current      -       Push buffered data out
+ *
+ *     Generate an audit message from the contents of @buf, which is owned by
+ *     the current task.  @buf->mutex must be locked.
+ */
+static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
+{
+       uid_t auid = audit_get_loginuid(current);
+       unsigned int sessionid = audit_get_sessionid(current);
+       tty_audit_buf_push(current, auid, sessionid, buf);
+}
+
+/**
+ *     tty_audit_exit  -       Handle a task exit
+ *
+ *     Make sure all buffered data is written out and deallocate the buffer.
+ *     Only needs to be called if current->signal->tty_audit_buf != %NULL.
+ */
+void tty_audit_exit(void)
+{
+       struct tty_audit_buf *buf;
+
+       spin_lock_irq(&current->sighand->siglock);
+       buf = current->signal->tty_audit_buf;
+       current->signal->tty_audit_buf = NULL;
+       spin_unlock_irq(&current->sighand->siglock);
+       if (!buf)
+               return;
+
+       mutex_lock(&buf->mutex);
+       tty_audit_buf_push_current(buf);
+       mutex_unlock(&buf->mutex);
+
+       tty_audit_buf_put(buf);
+}
+
+/**
+ *     tty_audit_fork  -       Copy TTY audit state for a new task
+ *
+ *     Set up TTY audit state in @sig from current.  @sig needs no locking.
+ */
+void tty_audit_fork(struct signal_struct *sig)
+{
+       spin_lock_irq(&current->sighand->siglock);
+       sig->audit_tty = current->signal->audit_tty;
+       spin_unlock_irq(&current->sighand->siglock);
+}
+
+/**
+ *     tty_audit_tiocsti       -       Log TIOCSTI
+ */
+void tty_audit_tiocsti(struct tty_struct *tty, char ch)
+{
+       struct tty_audit_buf *buf;
+       int major, minor, should_audit;
+
+       spin_lock_irq(&current->sighand->siglock);
+       should_audit = current->signal->audit_tty;
+       buf = current->signal->tty_audit_buf;
+       if (buf)
+               atomic_inc(&buf->count);
+       spin_unlock_irq(&current->sighand->siglock);
+
+       major = tty->driver->major;
+       minor = tty->driver->minor_start + tty->index;
+       if (buf) {
+               mutex_lock(&buf->mutex);
+               if (buf->major == major && buf->minor == minor)
+                       tty_audit_buf_push_current(buf);
+               mutex_unlock(&buf->mutex);
+               tty_audit_buf_put(buf);
+       }
+
+       if (should_audit && audit_enabled) {
+               uid_t auid;
+               unsigned int sessionid;
+
+               auid = audit_get_loginuid(current);
+               sessionid = audit_get_sessionid(current);
+               tty_audit_log("ioctl=TIOCSTI", current, auid, sessionid, major,
+                             minor, &ch, 1);
+       }
+}
+
+/**
+ * tty_audit_push_task -       Flush task's pending audit data
+ * @tsk:               task pointer
+ * @loginuid:          sender login uid
+ * @sessionid:         sender session id
+ *
+ * Called with a ref on @tsk held. Try to lock sighand and get a
+ * reference to the tty audit buffer if available.
+ * Flush the buffer or return an appropriate error code.
+ */
+int tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
+{
+       struct tty_audit_buf *buf = ERR_PTR(-EPERM);
+       unsigned long flags;
+
+       if (!lock_task_sighand(tsk, &flags))
+               return -ESRCH;
+
+       if (tsk->signal->audit_tty) {
+               buf = tsk->signal->tty_audit_buf;
+               if (buf)
+                       atomic_inc(&buf->count);
+       }
+       unlock_task_sighand(tsk, &flags);
+
+       /*
+        * Return 0 when signal->audit_tty set
+        * but tsk->signal->tty_audit_buf == NULL.
+        */
+       if (!buf || IS_ERR(buf))
+               return PTR_ERR(buf);
+
+       mutex_lock(&buf->mutex);
+       tty_audit_buf_push(tsk, loginuid, sessionid, buf);
+       mutex_unlock(&buf->mutex);
+
+       tty_audit_buf_put(buf);
+       return 0;
+}
+
+/**
+ *     tty_audit_buf_get       -       Get an audit buffer.
+ *
+ *     Get an audit buffer for @tty, allocate it if necessary.  Return %NULL
+ *     if TTY auditing is disabled or out of memory.  Otherwise, return a new
+ *     reference to the buffer.
+ */
+static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
+{
+       struct tty_audit_buf *buf, *buf2;
+
+       buf = NULL;
+       buf2 = NULL;
+       spin_lock_irq(&current->sighand->siglock);
+       if (likely(!current->signal->audit_tty))
+               goto out;
+       buf = current->signal->tty_audit_buf;
+       if (buf) {
+               atomic_inc(&buf->count);
+               goto out;
+       }
+       spin_unlock_irq(&current->sighand->siglock);
+
+       buf2 = tty_audit_buf_alloc(tty->driver->major,
+                                  tty->driver->minor_start + tty->index,
+                                  tty->icanon);
+       if (buf2 == NULL) {
+               audit_log_lost("out of memory in TTY auditing");
+               return NULL;
+       }
+
+       spin_lock_irq(&current->sighand->siglock);
+       if (!current->signal->audit_tty)
+               goto out;
+       buf = current->signal->tty_audit_buf;
+       if (!buf) {
+               current->signal->tty_audit_buf = buf2;
+               buf = buf2;
+               buf2 = NULL;
+       }
+       atomic_inc(&buf->count);
+       /* Fall through */
+ out:
+       spin_unlock_irq(&current->sighand->siglock);
+       if (buf2)
+               tty_audit_buf_free(buf2);
+       return buf;
+}
+
+/**
+ *     tty_audit_add_data      -       Add data for TTY auditing.
+ *
+ *     Audit @data of @size from @tty, if necessary.
+ */
+void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
+                       size_t size)
+{
+       struct tty_audit_buf *buf;
+       int major, minor;
+
+       if (unlikely(size == 0))
+               return;
+
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY
+           && tty->driver->subtype == PTY_TYPE_MASTER)
+               return;
+
+       buf = tty_audit_buf_get(tty);
+       if (!buf)
+               return;
+
+       mutex_lock(&buf->mutex);
+       major = tty->driver->major;
+       minor = tty->driver->minor_start + tty->index;
+       if (buf->major != major || buf->minor != minor
+           || buf->icanon != tty->icanon) {
+               tty_audit_buf_push_current(buf);
+               buf->major = major;
+               buf->minor = minor;
+               buf->icanon = tty->icanon;
+       }
+       do {
+               size_t run;
+
+               run = N_TTY_BUF_SIZE - buf->valid;
+               if (run > size)
+                       run = size;
+               memcpy(buf->data + buf->valid, data, run);
+               buf->valid += run;
+               data += run;
+               size -= run;
+               if (buf->valid == N_TTY_BUF_SIZE)
+                       tty_audit_buf_push_current(buf);
+       } while (size != 0);
+       mutex_unlock(&buf->mutex);
+       tty_audit_buf_put(buf);
+}
+
+/**
+ *     tty_audit_push  -       Push buffered data out
+ *
+ *     Make sure no audit data is pending for @tty on the current process.
+ */
+void tty_audit_push(struct tty_struct *tty)
+{
+       struct tty_audit_buf *buf;
+
+       spin_lock_irq(&current->sighand->siglock);
+       if (likely(!current->signal->audit_tty)) {
+               spin_unlock_irq(&current->sighand->siglock);
+               return;
+       }
+       buf = current->signal->tty_audit_buf;
+       if (buf)
+               atomic_inc(&buf->count);
+       spin_unlock_irq(&current->sighand->siglock);
+
+       if (buf) {
+               int major, minor;
+
+               major = tty->driver->major;
+               minor = tty->driver->minor_start + tty->index;
+               mutex_lock(&buf->mutex);
+               if (buf->major == major && buf->minor == minor)
+                       tty_audit_buf_push_current(buf);
+               mutex_unlock(&buf->mutex);
+               tty_audit_buf_put(buf);
+       }
+}
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
new file mode 100644 (file)
index 0000000..cc1e985
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+ * Tty buffer allocation management
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+/**
+ *     tty_buffer_free_all             -       free buffers used by a tty
+ *     @tty: tty to free from
+ *
+ *     Remove all the buffers pending on a tty whether queued with data
+ *     or in the free ring. Must be called when the tty is no longer in use
+ *
+ *     Locking: none
+ */
+
+void tty_buffer_free_all(struct tty_struct *tty)
+{
+       struct tty_buffer *thead;
+       while ((thead = tty->buf.head) != NULL) {
+               tty->buf.head = thead->next;
+               kfree(thead);
+       }
+       while ((thead = tty->buf.free) != NULL) {
+               tty->buf.free = thead->next;
+               kfree(thead);
+       }
+       tty->buf.tail = NULL;
+       tty->buf.memory_used = 0;
+}
+
+/**
+ *     tty_buffer_alloc        -       allocate a tty buffer
+ *     @tty: tty device
+ *     @size: desired size (characters)
+ *
+ *     Allocate a new tty buffer to hold the desired number of characters.
+ *     Return NULL if out of memory or the allocation would exceed the
+ *     per device queue
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
+{
+       struct tty_buffer *p;
+
+       if (tty->buf.memory_used + size > 65536)
+               return NULL;
+       p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
+       if (p == NULL)
+               return NULL;
+       p->used = 0;
+       p->size = size;
+       p->next = NULL;
+       p->commit = 0;
+       p->read = 0;
+       p->char_buf_ptr = (char *)(p->data);
+       p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
+       tty->buf.memory_used += size;
+       return p;
+}
+
+/**
+ *     tty_buffer_free         -       free a tty buffer
+ *     @tty: tty owning the buffer
+ *     @b: the buffer to free
+ *
+ *     Free a tty buffer, or add it to the free list according to our
+ *     internal strategy
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
+{
+       /* Dumb strategy for now - should keep some stats */
+       tty->buf.memory_used -= b->size;
+       WARN_ON(tty->buf.memory_used < 0);
+
+       if (b->size >= 512)
+               kfree(b);
+       else {
+               b->next = tty->buf.free;
+               tty->buf.free = b;
+       }
+}
+
+/**
+ *     __tty_buffer_flush              -       flush full tty buffers
+ *     @tty: tty to flush
+ *
+ *     flush all the buffers containing receive data. Caller must
+ *     hold the buffer lock and must have ensured no parallel flush to
+ *     ldisc is running.
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static void __tty_buffer_flush(struct tty_struct *tty)
+{
+       struct tty_buffer *thead;
+
+       while ((thead = tty->buf.head) != NULL) {
+               tty->buf.head = thead->next;
+               tty_buffer_free(tty, thead);
+       }
+       tty->buf.tail = NULL;
+}
+
+/**
+ *     tty_buffer_flush                -       flush full tty buffers
+ *     @tty: tty to flush
+ *
+ *     flush all the buffers containing receive data. If the buffer is
+ *     being processed by flush_to_ldisc then we defer the processing
+ *     to that function
+ *
+ *     Locking: none
+ */
+
+void tty_buffer_flush(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->buf.lock, flags);
+
+       /* If the data is being pushed to the tty layer then we can't
+          process it here. Instead set a flag and the flush_to_ldisc
+          path will process the flush request before it exits */
+       if (test_bit(TTY_FLUSHING, &tty->flags)) {
+               set_bit(TTY_FLUSHPENDING, &tty->flags);
+               spin_unlock_irqrestore(&tty->buf.lock, flags);
+               wait_event(tty->read_wait,
+                               test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
+               return;
+       } else
+               __tty_buffer_flush(tty);
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+}
+
+/**
+ *     tty_buffer_find         -       find a free tty buffer
+ *     @tty: tty owning the buffer
+ *     @size: characters wanted
+ *
+ *     Locate an existing suitable tty buffer or if we are lacking one then
+ *     allocate a new one. We round our buffers off in 256 character chunks
+ *     to get better allocation behaviour.
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
+{
+       struct tty_buffer **tbh = &tty->buf.free;
+       while ((*tbh) != NULL) {
+               struct tty_buffer *t = *tbh;
+               if (t->size >= size) {
+                       *tbh = t->next;
+                       t->next = NULL;
+                       t->used = 0;
+                       t->commit = 0;
+                       t->read = 0;
+                       tty->buf.memory_used += t->size;
+                       return t;
+               }
+               tbh = &((*tbh)->next);
+       }
+       /* Round the buffer size out */
+       size = (size + 0xFF) & ~0xFF;
+       return tty_buffer_alloc(tty, size);
+       /* Should possibly check if this fails for the largest buffer we
+          have queued and recycle that ? */
+}
+
+/**
+ *     tty_buffer_request_room         -       grow tty buffer if needed
+ *     @tty: tty structure
+ *     @size: size desired
+ *
+ *     Make at least size bytes of linear space available for the tty
+ *     buffer. If we fail return the size we managed to find.
+ *
+ *     Locking: Takes tty->buf.lock
+ */
+int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+{
+       struct tty_buffer *b, *n;
+       int left;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tty->buf.lock, flags);
+
+       /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
+          remove this conditional if its worth it. This would be invisible
+          to the callers */
+       if ((b = tty->buf.tail) != NULL)
+               left = b->size - b->used;
+       else
+               left = 0;
+
+       if (left < size) {
+               /* This is the slow path - looking for new buffers to use */
+               if ((n = tty_buffer_find(tty, size)) != NULL) {
+                       if (b != NULL) {
+                               b->next = n;
+                               b->commit = b->used;
+                       } else
+                               tty->buf.head = n;
+                       tty->buf.tail = n;
+               } else
+                       size = left;
+       }
+
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+       return size;
+}
+EXPORT_SYMBOL_GPL(tty_buffer_request_room);
+
+/**
+ *     tty_insert_flip_string_fixed_flag - Add characters to the tty buffer
+ *     @tty: tty structure
+ *     @chars: characters
+ *     @flag: flag value for each character
+ *     @size: size
+ *
+ *     Queue a series of bytes to the tty buffering. All the characters
+ *     passed are marked with the supplied flag. Returns the number added.
+ *
+ *     Locking: Called functions may take tty->buf.lock
+ */
+
+int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
+               const unsigned char *chars, char flag, size_t size)
+{
+       int copied = 0;
+       do {
+               int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
+               int space = tty_buffer_request_room(tty, goal);
+               struct tty_buffer *tb = tty->buf.tail;
+               /* If there is no space then tb may be NULL */
+               if (unlikely(space == 0))
+                       break;
+               memcpy(tb->char_buf_ptr + tb->used, chars, space);
+               memset(tb->flag_buf_ptr + tb->used, flag, space);
+               tb->used += space;
+               copied += space;
+               chars += space;
+               /* There is a small chance that we need to split the data over
+                  several buffers. If this is the case we must loop */
+       } while (unlikely(size > copied));
+       return copied;
+}
+EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag);
+
+/**
+ *     tty_insert_flip_string_flags    -       Add characters to the tty buffer
+ *     @tty: tty structure
+ *     @chars: characters
+ *     @flags: flag bytes
+ *     @size: size
+ *
+ *     Queue a series of bytes to the tty buffering. For each character
+ *     the flags array indicates the status of the character. Returns the
+ *     number added.
+ *
+ *     Locking: Called functions may take tty->buf.lock
+ */
+
+int tty_insert_flip_string_flags(struct tty_struct *tty,
+               const unsigned char *chars, const char *flags, size_t size)
+{
+       int copied = 0;
+       do {
+               int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
+               int space = tty_buffer_request_room(tty, goal);
+               struct tty_buffer *tb = tty->buf.tail;
+               /* If there is no space then tb may be NULL */
+               if (unlikely(space == 0))
+                       break;
+               memcpy(tb->char_buf_ptr + tb->used, chars, space);
+               memcpy(tb->flag_buf_ptr + tb->used, flags, space);
+               tb->used += space;
+               copied += space;
+               chars += space;
+               flags += space;
+               /* There is a small chance that we need to split the data over
+                  several buffers. If this is the case we must loop */
+       } while (unlikely(size > copied));
+       return copied;
+}
+EXPORT_SYMBOL(tty_insert_flip_string_flags);
+
+/**
+ *     tty_schedule_flip       -       push characters to ldisc
+ *     @tty: tty to push from
+ *
+ *     Takes any pending buffers and transfers their ownership to the
+ *     ldisc side of the queue. It then schedules those characters for
+ *     processing by the line discipline.
+ *
+ *     Locking: Takes tty->buf.lock
+ */
+
+void tty_schedule_flip(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->buf.lock, flags);
+       if (tty->buf.tail != NULL)
+               tty->buf.tail->commit = tty->buf.tail->used;
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+       schedule_delayed_work(&tty->buf.work, 1);
+}
+EXPORT_SYMBOL(tty_schedule_flip);
+
+/**
+ *     tty_prepare_flip_string         -       make room for characters
+ *     @tty: tty
+ *     @chars: return pointer for character write area
+ *     @size: desired size
+ *
+ *     Prepare a block of space in the buffer for data. Returns the length
+ *     available and buffer pointer to the space which is now allocated and
+ *     accounted for as ready for normal characters. This is used for drivers
+ *     that need their own block copy routines into the buffer. There is no
+ *     guarantee the buffer is a DMA target!
+ *
+ *     Locking: May call functions taking tty->buf.lock
+ */
+
+int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
+                                                               size_t size)
+{
+       int space = tty_buffer_request_room(tty, size);
+       if (likely(space)) {
+               struct tty_buffer *tb = tty->buf.tail;
+               *chars = tb->char_buf_ptr + tb->used;
+               memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+               tb->used += space;
+       }
+       return space;
+}
+EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
+
+/**
+ *     tty_prepare_flip_string_flags   -       make room for characters
+ *     @tty: tty
+ *     @chars: return pointer for character write area
+ *     @flags: return pointer for status flag write area
+ *     @size: desired size
+ *
+ *     Prepare a block of space in the buffer for data. Returns the length
+ *     available and buffer pointer to the space which is now allocated and
+ *     accounted for as ready for characters. This is used for drivers
+ *     that need their own block copy routines into the buffer. There is no
+ *     guarantee the buffer is a DMA target!
+ *
+ *     Locking: May call functions taking tty->buf.lock
+ */
+
+int tty_prepare_flip_string_flags(struct tty_struct *tty,
+                       unsigned char **chars, char **flags, size_t size)
+{
+       int space = tty_buffer_request_room(tty, size);
+       if (likely(space)) {
+               struct tty_buffer *tb = tty->buf.tail;
+               *chars = tb->char_buf_ptr + tb->used;
+               *flags = tb->flag_buf_ptr + tb->used;
+               tb->used += space;
+       }
+       return space;
+}
+EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
+
+
+
+/**
+ *     flush_to_ldisc
+ *     @work: tty structure passed from work queue.
+ *
+ *     This routine is called out of the software interrupt to flush data
+ *     from the buffer chain to the line discipline.
+ *
+ *     Locking: holds tty->buf.lock to guard buffer list. Drops the lock
+ *     while invoking the line discipline receive_buf method. The
+ *     receive_buf method is single threaded for each tty instance.
+ */
+
+static void flush_to_ldisc(struct work_struct *work)
+{
+       struct tty_struct *tty =
+               container_of(work, struct tty_struct, buf.work.work);
+       unsigned long   flags;
+       struct tty_ldisc *disc;
+
+       disc = tty_ldisc_ref(tty);
+       if (disc == NULL)       /*  !TTY_LDISC */
+               return;
+
+       spin_lock_irqsave(&tty->buf.lock, flags);
+
+       if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) {
+               struct tty_buffer *head;
+               while ((head = tty->buf.head) != NULL) {
+                       int count;
+                       char *char_buf;
+                       unsigned char *flag_buf;
+
+                       count = head->commit - head->read;
+                       if (!count) {
+                               if (head->next == NULL)
+                                       break;
+                               tty->buf.head = head->next;
+                               tty_buffer_free(tty, head);
+                               continue;
+                       }
+                       /* Ldisc or user is trying to flush the buffers
+                          we are feeding to the ldisc, stop feeding the
+                          line discipline as we want to empty the queue */
+                       if (test_bit(TTY_FLUSHPENDING, &tty->flags))
+                               break;
+                       if (!tty->receive_room) {
+                               schedule_delayed_work(&tty->buf.work, 1);
+                               break;
+                       }
+                       if (count > tty->receive_room)
+                               count = tty->receive_room;
+                       char_buf = head->char_buf_ptr + head->read;
+                       flag_buf = head->flag_buf_ptr + head->read;
+                       head->read += count;
+                       spin_unlock_irqrestore(&tty->buf.lock, flags);
+                       disc->ops->receive_buf(tty, char_buf,
+                                                       flag_buf, count);
+                       spin_lock_irqsave(&tty->buf.lock, flags);
+               }
+               clear_bit(TTY_FLUSHING, &tty->flags);
+       }
+
+       /* We may have a deferred request to flush the input buffer,
+          if so pull the chain under the lock and empty the queue */
+       if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
+               __tty_buffer_flush(tty);
+               clear_bit(TTY_FLUSHPENDING, &tty->flags);
+               wake_up(&tty->read_wait);
+       }
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+
+       tty_ldisc_deref(disc);
+}
+
+/**
+ *     tty_flush_to_ldisc
+ *     @tty: tty to push
+ *
+ *     Push the terminal flip buffers to the line discipline.
+ *
+ *     Must not be called from IRQ context.
+ */
+void tty_flush_to_ldisc(struct tty_struct *tty)
+{
+       flush_delayed_work(&tty->buf.work);
+}
+
+/**
+ *     tty_flip_buffer_push    -       terminal
+ *     @tty: tty to push
+ *
+ *     Queue a push of the terminal flip buffers to the line discipline. This
+ *     function must not be called from IRQ context if tty->low_latency is set.
+ *
+ *     In the event of the queue being busy for flipping the work will be
+ *     held off and retried later.
+ *
+ *     Locking: tty buffer lock. Driver locks in low latency mode.
+ */
+
+void tty_flip_buffer_push(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->buf.lock, flags);
+       if (tty->buf.tail != NULL)
+               tty->buf.tail->commit = tty->buf.tail->used;
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+
+       if (tty->low_latency)
+               flush_to_ldisc(&tty->buf.work.work);
+       else
+               schedule_delayed_work(&tty->buf.work, 1);
+}
+EXPORT_SYMBOL(tty_flip_buffer_push);
+
+/**
+ *     tty_buffer_init         -       prepare a tty buffer structure
+ *     @tty: tty to initialise
+ *
+ *     Set up the initial state of the buffer management for a tty device.
+ *     Must be called before the other tty buffer functions are used.
+ *
+ *     Locking: none
+ */
+
+void tty_buffer_init(struct tty_struct *tty)
+{
+       spin_lock_init(&tty->buf.lock);
+       tty->buf.head = NULL;
+       tty->buf.tail = NULL;
+       tty->buf.free = NULL;
+       tty->buf.memory_used = 0;
+       INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
+}
+
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
new file mode 100644 (file)
index 0000000..c05c5af
--- /dev/null
@@ -0,0 +1,3263 @@
+/*
+ *  linux/drivers/char/tty_io.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
+ * or rs-channels. It also implements echoing, cooked mode etc.
+ *
+ * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
+ *
+ * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
+ * tty_struct and tty_queue structures.  Previously there was an array
+ * of 256 tty_struct's which was statically allocated, and the
+ * tty_queue structures were allocated at boot time.  Both are now
+ * dynamically allocated only when the tty is open.
+ *
+ * Also restructured routines so that there is more of a separation
+ * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
+ * the low-level tty routines (serial.c, pty.c, console.c).  This
+ * makes for cleaner and more compact code.  -TYT, 9/17/92
+ *
+ * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
+ * which can be dynamically activated and de-activated by the line
+ * discipline handling modules (like SLIP).
+ *
+ * NOTE: pay no attention to the line discipline code (yet); its
+ * interface is still subject to change in this version...
+ * -- TYT, 1/31/92
+ *
+ * Added functionality to the OPOST tty handling.  No delays, but all
+ * other bits should be there.
+ *     -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
+ *
+ * Rewrote canonical mode and added more termios flags.
+ *     -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
+ *
+ * Reorganized FASYNC support so mouse code can share it.
+ *     -- ctm@ardi.com, 9Sep95
+ *
+ * New TIOCLINUX variants added.
+ *     -- mj@k332.feld.cvut.cz, 19-Nov-95
+ *
+ * Restrict vt switching via ioctl()
+ *      -- grif@cs.ucr.edu, 5-Dec-95
+ *
+ * Move console and virtual terminal code to more appropriate files,
+ * implement CONFIG_VT and generalize console device interface.
+ *     -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
+ *
+ * Rewrote tty_init_dev and tty_release_dev to eliminate races.
+ *     -- Bill Hawes <whawes@star.net>, June 97
+ *
+ * Added devfs support.
+ *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 13-Jan-1998
+ *
+ * Added support for a Unix98-style ptmx device.
+ *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
+ *
+ * Reduced memory usage for older ARM systems
+ *      -- Russell King <rmk@arm.linux.org.uk>
+ *
+ * Move do_SAK() into process context.  Less stack use in devfs functions.
+ * alloc_tty_struct() always uses kmalloc()
+ *                      -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01
+ */
+
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/devpts_fs.h>
+#include <linux/file.h>
+#include <linux/fdtable.h>
+#include <linux/console.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/kd.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/serial.h>
+
+#include <linux/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+
+#include <linux/kmod.h>
+#include <linux/nsproxy.h>
+
+#undef TTY_DEBUG_HANGUP
+
+#define TTY_PARANOIA_CHECK 1
+#define CHECK_TTY_COUNT 1
+
+struct ktermios tty_std_termios = {    /* for the benefit of tty drivers  */
+       .c_iflag = ICRNL | IXON,
+       .c_oflag = OPOST | ONLCR,
+       .c_cflag = B38400 | CS8 | CREAD | HUPCL,
+       .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
+                  ECHOCTL | ECHOKE | IEXTEN,
+       .c_cc = INIT_C_CC,
+       .c_ispeed = 38400,
+       .c_ospeed = 38400
+};
+
+EXPORT_SYMBOL(tty_std_termios);
+
+/* This list gets poked at by procfs and various bits of boot up code. This
+   could do with some rationalisation such as pulling the tty proc function
+   into this file */
+
+LIST_HEAD(tty_drivers);                        /* linked list of tty drivers */
+
+/* Mutex to protect creating and releasing a tty. This is shared with
+   vt.c for deeply disgusting hack reasons */
+DEFINE_MUTEX(tty_mutex);
+EXPORT_SYMBOL(tty_mutex);
+
+/* Spinlock to protect the tty->tty_files list */
+DEFINE_SPINLOCK(tty_files_lock);
+
+static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
+static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
+ssize_t redirected_tty_write(struct file *, const char __user *,
+                                                       size_t, loff_t *);
+static unsigned int tty_poll(struct file *, poll_table *);
+static int tty_open(struct inode *, struct file *);
+long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file *file, unsigned int cmd,
+                               unsigned long arg);
+#else
+#define tty_compat_ioctl NULL
+#endif
+static int __tty_fasync(int fd, struct file *filp, int on);
+static int tty_fasync(int fd, struct file *filp, int on);
+static void release_tty(struct tty_struct *tty, int idx);
+static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
+static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
+
+/**
+ *     alloc_tty_struct        -       allocate a tty object
+ *
+ *     Return a new empty tty structure. The data fields have not
+ *     been initialized in any way but has been zeroed
+ *
+ *     Locking: none
+ */
+
+struct tty_struct *alloc_tty_struct(void)
+{
+       return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
+}
+
+/**
+ *     free_tty_struct         -       free a disused tty
+ *     @tty: tty struct to free
+ *
+ *     Free the write buffers, tty queue and tty memory itself.
+ *
+ *     Locking: none. Must be called after tty is definitely unused
+ */
+
+void free_tty_struct(struct tty_struct *tty)
+{
+       if (tty->dev)
+               put_device(tty->dev);
+       kfree(tty->write_buf);
+       tty_buffer_free_all(tty);
+       kfree(tty);
+}
+
+static inline struct tty_struct *file_tty(struct file *file)
+{
+       return ((struct tty_file_private *)file->private_data)->tty;
+}
+
+/* Associate a new file with the tty structure */
+int tty_add_file(struct tty_struct *tty, struct file *file)
+{
+       struct tty_file_private *priv;
+
+       priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->tty = tty;
+       priv->file = file;
+       file->private_data = priv;
+
+       spin_lock(&tty_files_lock);
+       list_add(&priv->list, &tty->tty_files);
+       spin_unlock(&tty_files_lock);
+
+       return 0;
+}
+
+/* Delete file from its tty */
+void tty_del_file(struct file *file)
+{
+       struct tty_file_private *priv = file->private_data;
+
+       spin_lock(&tty_files_lock);
+       list_del(&priv->list);
+       spin_unlock(&tty_files_lock);
+       file->private_data = NULL;
+       kfree(priv);
+}
+
+
+#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)
+
+/**
+ *     tty_name        -       return tty naming
+ *     @tty: tty structure
+ *     @buf: buffer for output
+ *
+ *     Convert a tty structure into a name. The name reflects the kernel
+ *     naming policy and if udev is in use may not reflect user space
+ *
+ *     Locking: none
+ */
+
+char *tty_name(struct tty_struct *tty, char *buf)
+{
+       if (!tty) /* Hmm.  NULL pointer.  That's fun. */
+               strcpy(buf, "NULL tty");
+       else
+               strcpy(buf, tty->name);
+       return buf;
+}
+
+EXPORT_SYMBOL(tty_name);
+
+int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
+                             const char *routine)
+{
+#ifdef TTY_PARANOIA_CHECK
+       if (!tty) {
+               printk(KERN_WARNING
+                       "null TTY for (%d:%d) in %s\n",
+                       imajor(inode), iminor(inode), routine);
+               return 1;
+       }
+       if (tty->magic != TTY_MAGIC) {
+               printk(KERN_WARNING
+                       "bad magic number for tty struct (%d:%d) in %s\n",
+                       imajor(inode), iminor(inode), routine);
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+static int check_tty_count(struct tty_struct *tty, const char *routine)
+{
+#ifdef CHECK_TTY_COUNT
+       struct list_head *p;
+       int count = 0;
+
+       spin_lock(&tty_files_lock);
+       list_for_each(p, &tty->tty_files) {
+               count++;
+       }
+       spin_unlock(&tty_files_lock);
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_SLAVE &&
+           tty->link && tty->link->count)
+               count++;
+       if (tty->count != count) {
+               printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "
+                                   "!= #fd's(%d) in %s\n",
+                      tty->name, tty->count, count, routine);
+               return count;
+       }
+#endif
+       return 0;
+}
+
+/**
+ *     get_tty_driver          -       find device of a tty
+ *     @dev_t: device identifier
+ *     @index: returns the index of the tty
+ *
+ *     This routine returns a tty driver structure, given a device number
+ *     and also passes back the index number.
+ *
+ *     Locking: caller must hold tty_mutex
+ */
+
+static struct tty_driver *get_tty_driver(dev_t device, int *index)
+{
+       struct tty_driver *p;
+
+       list_for_each_entry(p, &tty_drivers, tty_drivers) {
+               dev_t base = MKDEV(p->major, p->minor_start);
+               if (device < base || device >= base + p->num)
+                       continue;
+               *index = device - base;
+               return tty_driver_kref_get(p);
+       }
+       return NULL;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+
+/**
+ *     tty_find_polling_driver -       find device of a polled tty
+ *     @name: name string to match
+ *     @line: pointer to resulting tty line nr
+ *
+ *     This routine returns a tty driver structure, given a name
+ *     and the condition that the tty driver is capable of polled
+ *     operation.
+ */
+struct tty_driver *tty_find_polling_driver(char *name, int *line)
+{
+       struct tty_driver *p, *res = NULL;
+       int tty_line = 0;
+       int len;
+       char *str, *stp;
+
+       for (str = name; *str; str++)
+               if ((*str >= '0' && *str <= '9') || *str == ',')
+                       break;
+       if (!*str)
+               return NULL;
+
+       len = str - name;
+       tty_line = simple_strtoul(str, &str, 10);
+
+       mutex_lock(&tty_mutex);
+       /* Search through the tty devices to look for a match */
+       list_for_each_entry(p, &tty_drivers, tty_drivers) {
+               if (strncmp(name, p->name, len) != 0)
+                       continue;
+               stp = str;
+               if (*stp == ',')
+                       stp++;
+               if (*stp == '\0')
+                       stp = NULL;
+
+               if (tty_line >= 0 && tty_line < p->num && p->ops &&
+                   p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {
+                       res = tty_driver_kref_get(p);
+                       *line = tty_line;
+                       break;
+               }
+       }
+       mutex_unlock(&tty_mutex);
+
+       return res;
+}
+EXPORT_SYMBOL_GPL(tty_find_polling_driver);
+#endif
+
+/**
+ *     tty_check_change        -       check for POSIX terminal changes
+ *     @tty: tty to check
+ *
+ *     If we try to write to, or set the state of, a terminal and we're
+ *     not in the foreground, send a SIGTTOU.  If the signal is blocked or
+ *     ignored, go ahead and perform the operation.  (POSIX 7.2)
+ *
+ *     Locking: ctrl_lock
+ */
+
+int tty_check_change(struct tty_struct *tty)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       if (current->signal->tty != tty)
+               return 0;
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+
+       if (!tty->pgrp) {
+               printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
+               goto out_unlock;
+       }
+       if (task_pgrp(current) == tty->pgrp)
+               goto out_unlock;
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       if (is_ignored(SIGTTOU))
+               goto out;
+       if (is_current_pgrp_orphaned()) {
+               ret = -EIO;
+               goto out;
+       }
+       kill_pgrp(task_pgrp(current), SIGTTOU, 1);
+       set_thread_flag(TIF_SIGPENDING);
+       ret = -ERESTARTSYS;
+out:
+       return ret;
+out_unlock:
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       return ret;
+}
+
+EXPORT_SYMBOL(tty_check_change);
+
+static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       return 0;
+}
+
+static ssize_t hung_up_tty_write(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       return -EIO;
+}
+
+/* No kernel lock held - none needed ;) */
+static unsigned int hung_up_tty_poll(struct file *filp, poll_table *wait)
+{
+       return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
+}
+
+static long hung_up_tty_ioctl(struct file *file, unsigned int cmd,
+               unsigned long arg)
+{
+       return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
+}
+
+static long hung_up_tty_compat_ioctl(struct file *file,
+                                    unsigned int cmd, unsigned long arg)
+{
+       return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
+}
+
+static const struct file_operations tty_fops = {
+       .llseek         = no_llseek,
+       .read           = tty_read,
+       .write          = tty_write,
+       .poll           = tty_poll,
+       .unlocked_ioctl = tty_ioctl,
+       .compat_ioctl   = tty_compat_ioctl,
+       .open           = tty_open,
+       .release        = tty_release,
+       .fasync         = tty_fasync,
+};
+
+static const struct file_operations console_fops = {
+       .llseek         = no_llseek,
+       .read           = tty_read,
+       .write          = redirected_tty_write,
+       .poll           = tty_poll,
+       .unlocked_ioctl = tty_ioctl,
+       .compat_ioctl   = tty_compat_ioctl,
+       .open           = tty_open,
+       .release        = tty_release,
+       .fasync         = tty_fasync,
+};
+
+static const struct file_operations hung_up_tty_fops = {
+       .llseek         = no_llseek,
+       .read           = hung_up_tty_read,
+       .write          = hung_up_tty_write,
+       .poll           = hung_up_tty_poll,
+       .unlocked_ioctl = hung_up_tty_ioctl,
+       .compat_ioctl   = hung_up_tty_compat_ioctl,
+       .release        = tty_release,
+};
+
+static DEFINE_SPINLOCK(redirect_lock);
+static struct file *redirect;
+
+/**
+ *     tty_wakeup      -       request more data
+ *     @tty: terminal
+ *
+ *     Internal and external helper for wakeups of tty. This function
+ *     informs the line discipline if present that the driver is ready
+ *     to receive more output data.
+ */
+
+void tty_wakeup(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld;
+
+       if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) {
+               ld = tty_ldisc_ref(tty);
+               if (ld) {
+                       if (ld->ops->write_wakeup)
+                               ld->ops->write_wakeup(tty);
+                       tty_ldisc_deref(ld);
+               }
+       }
+       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
+}
+
+EXPORT_SYMBOL_GPL(tty_wakeup);
+
+/**
+ *     __tty_hangup            -       actual handler for hangup events
+ *     @work: tty device
+ *
+ *     This can be called by the "eventd" kernel thread.  That is process
+ *     synchronous but doesn't hold any locks, so we need to make sure we
+ *     have the appropriate locks for what we're doing.
+ *
+ *     The hangup event clears any pending redirections onto the hung up
+ *     device. It ensures future writes will error and it does the needed
+ *     line discipline hangup and signal delivery. The tty object itself
+ *     remains intact.
+ *
+ *     Locking:
+ *             BTM
+ *               redirect lock for undoing redirection
+ *               file list lock for manipulating list of ttys
+ *               tty_ldisc_lock from called functions
+ *               termios_mutex resetting termios data
+ *               tasklist_lock to walk task list for hangup event
+ *                 ->siglock to protect ->signal/->sighand
+ */
+void __tty_hangup(struct tty_struct *tty)
+{
+       struct file *cons_filp = NULL;
+       struct file *filp, *f = NULL;
+       struct task_struct *p;
+       struct tty_file_private *priv;
+       int    closecount = 0, n;
+       unsigned long flags;
+       int refs = 0;
+
+       if (!tty)
+               return;
+
+
+       spin_lock(&redirect_lock);
+       if (redirect && file_tty(redirect) == tty) {
+               f = redirect;
+               redirect = NULL;
+       }
+       spin_unlock(&redirect_lock);
+
+       tty_lock();
+
+       /* inuse_filps is protected by the single tty lock,
+          this really needs to change if we want to flush the
+          workqueue with the lock held */
+       check_tty_count(tty, "tty_hangup");
+
+       spin_lock(&tty_files_lock);
+       /* This breaks for file handles being sent over AF_UNIX sockets ? */
+       list_for_each_entry(priv, &tty->tty_files, list) {
+               filp = priv->file;
+               if (filp->f_op->write == redirected_tty_write)
+                       cons_filp = filp;
+               if (filp->f_op->write != tty_write)
+                       continue;
+               closecount++;
+               __tty_fasync(-1, filp, 0);      /* can't block */
+               filp->f_op = &hung_up_tty_fops;
+       }
+       spin_unlock(&tty_files_lock);
+
+       tty_ldisc_hangup(tty);
+
+       read_lock(&tasklist_lock);
+       if (tty->session) {
+               do_each_pid_task(tty->session, PIDTYPE_SID, p) {
+                       spin_lock_irq(&p->sighand->siglock);
+                       if (p->signal->tty == tty) {
+                               p->signal->tty = NULL;
+                               /* We defer the dereferences outside fo
+                                  the tasklist lock */
+                               refs++;
+                       }
+                       if (!p->signal->leader) {
+                               spin_unlock_irq(&p->sighand->siglock);
+                               continue;
+                       }
+                       __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
+                       __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
+                       put_pid(p->signal->tty_old_pgrp);  /* A noop */
+                       spin_lock_irqsave(&tty->ctrl_lock, flags);
+                       if (tty->pgrp)
+                               p->signal->tty_old_pgrp = get_pid(tty->pgrp);
+                       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+                       spin_unlock_irq(&p->sighand->siglock);
+               } while_each_pid_task(tty->session, PIDTYPE_SID, p);
+       }
+       read_unlock(&tasklist_lock);
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       clear_bit(TTY_THROTTLED, &tty->flags);
+       clear_bit(TTY_PUSH, &tty->flags);
+       clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       put_pid(tty->session);
+       put_pid(tty->pgrp);
+       tty->session = NULL;
+       tty->pgrp = NULL;
+       tty->ctrl_status = 0;
+       set_bit(TTY_HUPPED, &tty->flags);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+       /* Account for the p->signal references we killed */
+       while (refs--)
+               tty_kref_put(tty);
+
+       /*
+        * If one of the devices matches a console pointer, we
+        * cannot just call hangup() because that will cause
+        * tty->count and state->count to go out of sync.
+        * So we just call close() the right number of times.
+        */
+       if (cons_filp) {
+               if (tty->ops->close)
+                       for (n = 0; n < closecount; n++)
+                               tty->ops->close(tty, cons_filp);
+       } else if (tty->ops->hangup)
+               (tty->ops->hangup)(tty);
+       /*
+        * We don't want to have driver/ldisc interactions beyond
+        * the ones we did here. The driver layer expects no
+        * calls after ->hangup() from the ldisc side. However we
+        * can't yet guarantee all that.
+        */
+       set_bit(TTY_HUPPED, &tty->flags);
+       tty_ldisc_enable(tty);
+
+       tty_unlock();
+
+       if (f)
+               fput(f);
+}
+
+static void do_tty_hangup(struct work_struct *work)
+{
+       struct tty_struct *tty =
+               container_of(work, struct tty_struct, hangup_work);
+
+       __tty_hangup(tty);
+}
+
+/**
+ *     tty_hangup              -       trigger a hangup event
+ *     @tty: tty to hangup
+ *
+ *     A carrier loss (virtual or otherwise) has occurred on this like
+ *     schedule a hangup sequence to run after this event.
+ */
+
+void tty_hangup(struct tty_struct *tty)
+{
+#ifdef TTY_DEBUG_HANGUP
+       char    buf[64];
+       printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf));
+#endif
+       schedule_work(&tty->hangup_work);
+}
+
+EXPORT_SYMBOL(tty_hangup);
+
+/**
+ *     tty_vhangup             -       process vhangup
+ *     @tty: tty to hangup
+ *
+ *     The user has asked via system call for the terminal to be hung up.
+ *     We do this synchronously so that when the syscall returns the process
+ *     is complete. That guarantee is necessary for security reasons.
+ */
+
+void tty_vhangup(struct tty_struct *tty)
+{
+#ifdef TTY_DEBUG_HANGUP
+       char    buf[64];
+
+       printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
+#endif
+       __tty_hangup(tty);
+}
+
+EXPORT_SYMBOL(tty_vhangup);
+
+
+/**
+ *     tty_vhangup_self        -       process vhangup for own ctty
+ *
+ *     Perform a vhangup on the current controlling tty
+ */
+
+void tty_vhangup_self(void)
+{
+       struct tty_struct *tty;
+
+       tty = get_current_tty();
+       if (tty) {
+               tty_vhangup(tty);
+               tty_kref_put(tty);
+       }
+}
+
+/**
+ *     tty_hung_up_p           -       was tty hung up
+ *     @filp: file pointer of tty
+ *
+ *     Return true if the tty has been subject to a vhangup or a carrier
+ *     loss
+ */
+
+int tty_hung_up_p(struct file *filp)
+{
+       return (filp->f_op == &hung_up_tty_fops);
+}
+
+EXPORT_SYMBOL(tty_hung_up_p);
+
+static void session_clear_tty(struct pid *session)
+{
+       struct task_struct *p;
+       do_each_pid_task(session, PIDTYPE_SID, p) {
+               proc_clear_tty(p);
+       } while_each_pid_task(session, PIDTYPE_SID, p);
+}
+
+/**
+ *     disassociate_ctty       -       disconnect controlling tty
+ *     @on_exit: true if exiting so need to "hang up" the session
+ *
+ *     This function is typically called only by the session leader, when
+ *     it wants to disassociate itself from its controlling tty.
+ *
+ *     It performs the following functions:
+ *     (1)  Sends a SIGHUP and SIGCONT to the foreground process group
+ *     (2)  Clears the tty from being controlling the session
+ *     (3)  Clears the controlling tty for all processes in the
+ *             session group.
+ *
+ *     The argument on_exit is set to 1 if called when a process is
+ *     exiting; it is 0 if called by the ioctl TIOCNOTTY.
+ *
+ *     Locking:
+ *             BTM is taken for hysterical raisins, and held when
+ *               called from no_tty().
+ *               tty_mutex is taken to protect tty
+ *               ->siglock is taken to protect ->signal/->sighand
+ *               tasklist_lock is taken to walk process list for sessions
+ *                 ->siglock is taken to protect ->signal/->sighand
+ */
+
+void disassociate_ctty(int on_exit)
+{
+       struct tty_struct *tty;
+       struct pid *tty_pgrp = NULL;
+
+       if (!current->signal->leader)
+               return;
+
+       tty = get_current_tty();
+       if (tty) {
+               tty_pgrp = get_pid(tty->pgrp);
+               if (on_exit) {
+                       if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
+                               tty_vhangup(tty);
+               }
+               tty_kref_put(tty);
+       } else if (on_exit) {
+               struct pid *old_pgrp;
+               spin_lock_irq(&current->sighand->siglock);
+               old_pgrp = current->signal->tty_old_pgrp;
+               current->signal->tty_old_pgrp = NULL;
+               spin_unlock_irq(&current->sighand->siglock);
+               if (old_pgrp) {
+                       kill_pgrp(old_pgrp, SIGHUP, on_exit);
+                       kill_pgrp(old_pgrp, SIGCONT, on_exit);
+                       put_pid(old_pgrp);
+               }
+               return;
+       }
+       if (tty_pgrp) {
+               kill_pgrp(tty_pgrp, SIGHUP, on_exit);
+               if (!on_exit)
+                       kill_pgrp(tty_pgrp, SIGCONT, on_exit);
+               put_pid(tty_pgrp);
+       }
+
+       spin_lock_irq(&current->sighand->siglock);
+       put_pid(current->signal->tty_old_pgrp);
+       current->signal->tty_old_pgrp = NULL;
+       spin_unlock_irq(&current->sighand->siglock);
+
+       tty = get_current_tty();
+       if (tty) {
+               unsigned long flags;
+               spin_lock_irqsave(&tty->ctrl_lock, flags);
+               put_pid(tty->session);
+               put_pid(tty->pgrp);
+               tty->session = NULL;
+               tty->pgrp = NULL;
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               tty_kref_put(tty);
+       } else {
+#ifdef TTY_DEBUG_HANGUP
+               printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
+                      " = NULL", tty);
+#endif
+       }
+
+       /* Now clear signal->tty under the lock */
+       read_lock(&tasklist_lock);
+       session_clear_tty(task_session(current));
+       read_unlock(&tasklist_lock);
+}
+
+/**
+ *
+ *     no_tty  - Ensure the current process does not have a controlling tty
+ */
+void no_tty(void)
+{
+       struct task_struct *tsk = current;
+       tty_lock();
+       disassociate_ctty(0);
+       tty_unlock();
+       proc_clear_tty(tsk);
+}
+
+
+/**
+ *     stop_tty        -       propagate flow control
+ *     @tty: tty to stop
+ *
+ *     Perform flow control to the driver. For PTY/TTY pairs we
+ *     must also propagate the TIOCKPKT status. May be called
+ *     on an already stopped device and will not re-call the driver
+ *     method.
+ *
+ *     This functionality is used by both the line disciplines for
+ *     halting incoming flow and by the driver. It may therefore be
+ *     called from any context, may be under the tty atomic_write_lock
+ *     but not always.
+ *
+ *     Locking:
+ *             Uses the tty control lock internally
+ */
+
+void stop_tty(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       if (tty->stopped) {
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               return;
+       }
+       tty->stopped = 1;
+       if (tty->link && tty->link->packet) {
+               tty->ctrl_status &= ~TIOCPKT_START;
+               tty->ctrl_status |= TIOCPKT_STOP;
+               wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
+       }
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       if (tty->ops->stop)
+               (tty->ops->stop)(tty);
+}
+
+EXPORT_SYMBOL(stop_tty);
+
+/**
+ *     start_tty       -       propagate flow control
+ *     @tty: tty to start
+ *
+ *     Start a tty that has been stopped if at all possible. Perform
+ *     any necessary wakeups and propagate the TIOCPKT status. If this
+ *     is the tty was previous stopped and is being started then the
+ *     driver start method is invoked and the line discipline woken.
+ *
+ *     Locking:
+ *             ctrl_lock
+ */
+
+void start_tty(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       if (!tty->stopped || tty->flow_stopped) {
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               return;
+       }
+       tty->stopped = 0;
+       if (tty->link && tty->link->packet) {
+               tty->ctrl_status &= ~TIOCPKT_STOP;
+               tty->ctrl_status |= TIOCPKT_START;
+               wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
+       }
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       if (tty->ops->start)
+               (tty->ops->start)(tty);
+       /* If we have a running line discipline it may need kicking */
+       tty_wakeup(tty);
+}
+
+EXPORT_SYMBOL(start_tty);
+
+/**
+ *     tty_read        -       read method for tty device files
+ *     @file: pointer to tty file
+ *     @buf: user buffer
+ *     @count: size of user buffer
+ *     @ppos: unused
+ *
+ *     Perform the read system call function on this terminal device. Checks
+ *     for hung up devices before calling the line discipline method.
+ *
+ *     Locking:
+ *             Locks the line discipline internally while needed. Multiple
+ *     read calls may be outstanding in parallel.
+ */
+
+static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
+                       loff_t *ppos)
+{
+       int i;
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct tty_struct *tty = file_tty(file);
+       struct tty_ldisc *ld;
+
+       if (tty_paranoia_check(tty, inode, "tty_read"))
+               return -EIO;
+       if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
+               return -EIO;
+
+       /* We want to wait for the line discipline to sort out in this
+          situation */
+       ld = tty_ldisc_ref_wait(tty);
+       if (ld->ops->read)
+               i = (ld->ops->read)(tty, file, buf, count);
+       else
+               i = -EIO;
+       tty_ldisc_deref(ld);
+       if (i > 0)
+               inode->i_atime = current_fs_time(inode->i_sb);
+       return i;
+}
+
+void tty_write_unlock(struct tty_struct *tty)
+{
+       mutex_unlock(&tty->atomic_write_lock);
+       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
+}
+
+int tty_write_lock(struct tty_struct *tty, int ndelay)
+{
+       if (!mutex_trylock(&tty->atomic_write_lock)) {
+               if (ndelay)
+                       return -EAGAIN;
+               if (mutex_lock_interruptible(&tty->atomic_write_lock))
+                       return -ERESTARTSYS;
+       }
+       return 0;
+}
+
+/*
+ * Split writes up in sane blocksizes to avoid
+ * denial-of-service type attacks
+ */
+static inline ssize_t do_tty_write(
+       ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
+       struct tty_struct *tty,
+       struct file *file,
+       const char __user *buf,
+       size_t count)
+{
+       ssize_t ret, written = 0;
+       unsigned int chunk;
+
+       ret = tty_write_lock(tty, file->f_flags & O_NDELAY);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * We chunk up writes into a temporary buffer. This
+        * simplifies low-level drivers immensely, since they
+        * don't have locking issues and user mode accesses.
+        *
+        * But if TTY_NO_WRITE_SPLIT is set, we should use a
+        * big chunk-size..
+        *
+        * The default chunk-size is 2kB, because the NTTY
+        * layer has problems with bigger chunks. It will
+        * claim to be able to handle more characters than
+        * it actually does.
+        *
+        * FIXME: This can probably go away now except that 64K chunks
+        * are too likely to fail unless switched to vmalloc...
+        */
+       chunk = 2048;
+       if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags))
+               chunk = 65536;
+       if (count < chunk)
+               chunk = count;
+
+       /* write_buf/write_cnt is protected by the atomic_write_lock mutex */
+       if (tty->write_cnt < chunk) {
+               unsigned char *buf_chunk;
+
+               if (chunk < 1024)
+                       chunk = 1024;
+
+               buf_chunk = kmalloc(chunk, GFP_KERNEL);
+               if (!buf_chunk) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               kfree(tty->write_buf);
+               tty->write_cnt = chunk;
+               tty->write_buf = buf_chunk;
+       }
+
+       /* Do the write .. */
+       for (;;) {
+               size_t size = count;
+               if (size > chunk)
+                       size = chunk;
+               ret = -EFAULT;
+               if (copy_from_user(tty->write_buf, buf, size))
+                       break;
+               ret = write(tty, file, tty->write_buf, size);
+               if (ret <= 0)
+                       break;
+               written += ret;
+               buf += ret;
+               count -= ret;
+               if (!count)
+                       break;
+               ret = -ERESTARTSYS;
+               if (signal_pending(current))
+                       break;
+               cond_resched();
+       }
+       if (written) {
+               struct inode *inode = file->f_path.dentry->d_inode;
+               inode->i_mtime = current_fs_time(inode->i_sb);
+               ret = written;
+       }
+out:
+       tty_write_unlock(tty);
+       return ret;
+}
+
+/**
+ * tty_write_message - write a message to a certain tty, not just the console.
+ * @tty: the destination tty_struct
+ * @msg: the message to write
+ *
+ * This is used for messages that need to be redirected to a specific tty.
+ * We don't put it into the syslog queue right now maybe in the future if
+ * really needed.
+ *
+ * We must still hold the BTM and test the CLOSING flag for the moment.
+ */
+
+void tty_write_message(struct tty_struct *tty, char *msg)
+{
+       if (tty) {
+               mutex_lock(&tty->atomic_write_lock);
+               tty_lock();
+               if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
+                       tty_unlock();
+                       tty->ops->write(tty, msg, strlen(msg));
+               } else
+                       tty_unlock();
+               tty_write_unlock(tty);
+       }
+       return;
+}
+
+
+/**
+ *     tty_write               -       write method for tty device file
+ *     @file: tty file pointer
+ *     @buf: user data to write
+ *     @count: bytes to write
+ *     @ppos: unused
+ *
+ *     Write data to a tty device via the line discipline.
+ *
+ *     Locking:
+ *             Locks the line discipline as required
+ *             Writes to the tty driver are serialized by the atomic_write_lock
+ *     and are then processed in chunks to the device. The line discipline
+ *     write method will not be invoked in parallel for each device.
+ */
+
+static ssize_t tty_write(struct file *file, const char __user *buf,
+                                               size_t count, loff_t *ppos)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct tty_struct *tty = file_tty(file);
+       struct tty_ldisc *ld;
+       ssize_t ret;
+
+       if (tty_paranoia_check(tty, inode, "tty_write"))
+               return -EIO;
+       if (!tty || !tty->ops->write ||
+               (test_bit(TTY_IO_ERROR, &tty->flags)))
+                       return -EIO;
+       /* Short term debug to catch buggy drivers */
+       if (tty->ops->write_room == NULL)
+               printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
+                       tty->driver->name);
+       ld = tty_ldisc_ref_wait(tty);
+       if (!ld->ops->write)
+               ret = -EIO;
+       else
+               ret = do_tty_write(ld->ops->write, tty, file, buf, count);
+       tty_ldisc_deref(ld);
+       return ret;
+}
+
+ssize_t redirected_tty_write(struct file *file, const char __user *buf,
+                                               size_t count, loff_t *ppos)
+{
+       struct file *p = NULL;
+
+       spin_lock(&redirect_lock);
+       if (redirect) {
+               get_file(redirect);
+               p = redirect;
+       }
+       spin_unlock(&redirect_lock);
+
+       if (p) {
+               ssize_t res;
+               res = vfs_write(p, buf, count, &p->f_pos);
+               fput(p);
+               return res;
+       }
+       return tty_write(file, buf, count, ppos);
+}
+
+static char ptychar[] = "pqrstuvwxyzabcde";
+
+/**
+ *     pty_line_name   -       generate name for a pty
+ *     @driver: the tty driver in use
+ *     @index: the minor number
+ *     @p: output buffer of at least 6 bytes
+ *
+ *     Generate a name from a driver reference and write it to the output
+ *     buffer.
+ *
+ *     Locking: None
+ */
+static void pty_line_name(struct tty_driver *driver, int index, char *p)
+{
+       int i = index + driver->name_base;
+       /* ->name is initialized to "ttyp", but "tty" is expected */
+       sprintf(p, "%s%c%x",
+               driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name,
+               ptychar[i >> 4 & 0xf], i & 0xf);
+}
+
+/**
+ *     tty_line_name   -       generate name for a tty
+ *     @driver: the tty driver in use
+ *     @index: the minor number
+ *     @p: output buffer of at least 7 bytes
+ *
+ *     Generate a name from a driver reference and write it to the output
+ *     buffer.
+ *
+ *     Locking: None
+ */
+static void tty_line_name(struct tty_driver *driver, int index, char *p)
+{
+       sprintf(p, "%s%d", driver->name, index + driver->name_base);
+}
+
+/**
+ *     tty_driver_lookup_tty() - find an existing tty, if any
+ *     @driver: the driver for the tty
+ *     @idx:    the minor number
+ *
+ *     Return the tty, if found or ERR_PTR() otherwise.
+ *
+ *     Locking: tty_mutex must be held. If tty is found, the mutex must
+ *     be held until the 'fast-open' is also done. Will change once we
+ *     have refcounting in the driver and per driver locking
+ */
+static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
+               struct inode *inode, int idx)
+{
+       struct tty_struct *tty;
+
+       if (driver->ops->lookup)
+               return driver->ops->lookup(driver, inode, idx);
+
+       tty = driver->ttys[idx];
+       return tty;
+}
+
+/**
+ *     tty_init_termios        -  helper for termios setup
+ *     @tty: the tty to set up
+ *
+ *     Initialise the termios structures for this tty. Thus runs under
+ *     the tty_mutex currently so we can be relaxed about ordering.
+ */
+
+int tty_init_termios(struct tty_struct *tty)
+{
+       struct ktermios *tp;
+       int idx = tty->index;
+
+       tp = tty->driver->termios[idx];
+       if (tp == NULL) {
+               tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+               if (tp == NULL)
+                       return -ENOMEM;
+               memcpy(tp, &tty->driver->init_termios,
+                                               sizeof(struct ktermios));
+               tty->driver->termios[idx] = tp;
+       }
+       tty->termios = tp;
+       tty->termios_locked = tp + 1;
+
+       /* Compatibility until drivers always set this */
+       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
+       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tty_init_termios);
+
+/**
+ *     tty_driver_install_tty() - install a tty entry in the driver
+ *     @driver: the driver for the tty
+ *     @tty: the tty
+ *
+ *     Install a tty object into the driver tables. The tty->index field
+ *     will be set by the time this is called. This method is responsible
+ *     for ensuring any need additional structures are allocated and
+ *     configured.
+ *
+ *     Locking: tty_mutex for now
+ */
+static int tty_driver_install_tty(struct tty_driver *driver,
+                                               struct tty_struct *tty)
+{
+       int idx = tty->index;
+       int ret;
+
+       if (driver->ops->install) {
+               ret = driver->ops->install(driver, tty);
+               return ret;
+       }
+
+       if (tty_init_termios(tty) == 0) {
+               tty_driver_kref_get(driver);
+               tty->count++;
+               driver->ttys[idx] = tty;
+               return 0;
+       }
+       return -ENOMEM;
+}
+
+/**
+ *     tty_driver_remove_tty() - remove a tty from the driver tables
+ *     @driver: the driver for the tty
+ *     @idx:    the minor number
+ *
+ *     Remvoe a tty object from the driver tables. The tty->index field
+ *     will be set by the time this is called.
+ *
+ *     Locking: tty_mutex for now
+ */
+static void tty_driver_remove_tty(struct tty_driver *driver,
+                                               struct tty_struct *tty)
+{
+       if (driver->ops->remove)
+               driver->ops->remove(driver, tty);
+       else
+               driver->ttys[tty->index] = NULL;
+}
+
+/*
+ *     tty_reopen()    - fast re-open of an open tty
+ *     @tty    - the tty to open
+ *
+ *     Return 0 on success, -errno on error.
+ *
+ *     Locking: tty_mutex must be held from the time the tty was found
+ *              till this open completes.
+ */
+static int tty_reopen(struct tty_struct *tty)
+{
+       struct tty_driver *driver = tty->driver;
+
+       if (test_bit(TTY_CLOSING, &tty->flags))
+               return -EIO;
+
+       if (driver->type == TTY_DRIVER_TYPE_PTY &&
+           driver->subtype == PTY_TYPE_MASTER) {
+               /*
+                * special case for PTY masters: only one open permitted,
+                * and the slave side open count is incremented as well.
+                */
+               if (tty->count)
+                       return -EIO;
+
+               tty->link->count++;
+       }
+       tty->count++;
+       tty->driver = driver; /* N.B. why do this every time?? */
+
+       mutex_lock(&tty->ldisc_mutex);
+       WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
+       mutex_unlock(&tty->ldisc_mutex);
+
+       return 0;
+}
+
+/**
+ *     tty_init_dev            -       initialise a tty device
+ *     @driver: tty driver we are opening a device on
+ *     @idx: device index
+ *     @ret_tty: returned tty structure
+ *     @first_ok: ok to open a new device (used by ptmx)
+ *
+ *     Prepare a tty device. This may not be a "new" clean device but
+ *     could also be an active device. The pty drivers require special
+ *     handling because of this.
+ *
+ *     Locking:
+ *             The function is called under the tty_mutex, which
+ *     protects us from the tty struct or driver itself going away.
+ *
+ *     On exit the tty device has the line discipline attached and
+ *     a reference count of 1. If a pair was created for pty/tty use
+ *     and the other was a pty master then it too has a reference count of 1.
+ *
+ * WSH 06/09/97: Rewritten to remove races and properly clean up after a
+ * failed open.  The new code protects the open with a mutex, so it's
+ * really quite straightforward.  The mutex locking can probably be
+ * relaxed for the (most common) case of reopening a tty.
+ */
+
+struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
+                                                               int first_ok)
+{
+       struct tty_struct *tty;
+       int retval;
+
+       /* Check if pty master is being opened multiple times */
+       if (driver->subtype == PTY_TYPE_MASTER &&
+               (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
+               return ERR_PTR(-EIO);
+       }
+
+       /*
+        * First time open is complex, especially for PTY devices.
+        * This code guarantees that either everything succeeds and the
+        * TTY is ready for operation, or else the table slots are vacated
+        * and the allocated memory released.  (Except that the termios
+        * and locked termios may be retained.)
+        */
+
+       if (!try_module_get(driver->owner))
+               return ERR_PTR(-ENODEV);
+
+       tty = alloc_tty_struct();
+       if (!tty)
+               goto fail_no_mem;
+       initialize_tty_struct(tty, driver, idx);
+
+       retval = tty_driver_install_tty(driver, tty);
+       if (retval < 0) {
+               free_tty_struct(tty);
+               module_put(driver->owner);
+               return ERR_PTR(retval);
+       }
+
+       /*
+        * Structures all installed ... call the ldisc open routines.
+        * If we fail here just call release_tty to clean up.  No need
+        * to decrement the use counts, as release_tty doesn't care.
+        */
+       retval = tty_ldisc_setup(tty, tty->link);
+       if (retval)
+               goto release_mem_out;
+       return tty;
+
+fail_no_mem:
+       module_put(driver->owner);
+       return ERR_PTR(-ENOMEM);
+
+       /* call the tty release_tty routine to clean out this slot */
+release_mem_out:
+       if (printk_ratelimit())
+               printk(KERN_INFO "tty_init_dev: ldisc open failed, "
+                                "clearing slot %d\n", idx);
+       release_tty(tty, idx);
+       return ERR_PTR(retval);
+}
+
+void tty_free_termios(struct tty_struct *tty)
+{
+       struct ktermios *tp;
+       int idx = tty->index;
+       /* Kill this flag and push into drivers for locking etc */
+       if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
+               /* FIXME: Locking on ->termios array */
+               tp = tty->termios;
+               tty->driver->termios[idx] = NULL;
+               kfree(tp);
+       }
+}
+EXPORT_SYMBOL(tty_free_termios);
+
+void tty_shutdown(struct tty_struct *tty)
+{
+       tty_driver_remove_tty(tty->driver, tty);
+       tty_free_termios(tty);
+}
+EXPORT_SYMBOL(tty_shutdown);
+
+/**
+ *     release_one_tty         -       release tty structure memory
+ *     @kref: kref of tty we are obliterating
+ *
+ *     Releases memory associated with a tty structure, and clears out the
+ *     driver table slots. This function is called when a device is no longer
+ *     in use. It also gets called when setup of a device fails.
+ *
+ *     Locking:
+ *             tty_mutex - sometimes only
+ *             takes the file list lock internally when working on the list
+ *     of ttys that the driver keeps.
+ *
+ *     This method gets called from a work queue so that the driver private
+ *     cleanup ops can sleep (needed for USB at least)
+ */
+static void release_one_tty(struct work_struct *work)
+{
+       struct tty_struct *tty =
+               container_of(work, struct tty_struct, hangup_work);
+       struct tty_driver *driver = tty->driver;
+
+       if (tty->ops->cleanup)
+               tty->ops->cleanup(tty);
+
+       tty->magic = 0;
+       tty_driver_kref_put(driver);
+       module_put(driver->owner);
+
+       spin_lock(&tty_files_lock);
+       list_del_init(&tty->tty_files);
+       spin_unlock(&tty_files_lock);
+
+       put_pid(tty->pgrp);
+       put_pid(tty->session);
+       free_tty_struct(tty);
+}
+
+static void queue_release_one_tty(struct kref *kref)
+{
+       struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
+
+       if (tty->ops->shutdown)
+               tty->ops->shutdown(tty);
+       else
+               tty_shutdown(tty);
+
+       /* The hangup queue is now free so we can reuse it rather than
+          waste a chunk of memory for each port */
+       INIT_WORK(&tty->hangup_work, release_one_tty);
+       schedule_work(&tty->hangup_work);
+}
+
+/**
+ *     tty_kref_put            -       release a tty kref
+ *     @tty: tty device
+ *
+ *     Release a reference to a tty device and if need be let the kref
+ *     layer destruct the object for us
+ */
+
+void tty_kref_put(struct tty_struct *tty)
+{
+       if (tty)
+               kref_put(&tty->kref, queue_release_one_tty);
+}
+EXPORT_SYMBOL(tty_kref_put);
+
+/**
+ *     release_tty             -       release tty structure memory
+ *
+ *     Release both @tty and a possible linked partner (think pty pair),
+ *     and decrement the refcount of the backing module.
+ *
+ *     Locking:
+ *             tty_mutex - sometimes only
+ *             takes the file list lock internally when working on the list
+ *     of ttys that the driver keeps.
+ *             FIXME: should we require tty_mutex is held here ??
+ *
+ */
+static void release_tty(struct tty_struct *tty, int idx)
+{
+       /* This should always be true but check for the moment */
+       WARN_ON(tty->index != idx);
+
+       if (tty->link)
+               tty_kref_put(tty->link);
+       tty_kref_put(tty);
+}
+
+/**
+ *     tty_release             -       vfs callback for close
+ *     @inode: inode of tty
+ *     @filp: file pointer for handle to tty
+ *
+ *     Called the last time each file handle is closed that references
+ *     this tty. There may however be several such references.
+ *
+ *     Locking:
+ *             Takes bkl. See tty_release_dev
+ *
+ * Even releasing the tty structures is a tricky business.. We have
+ * to be very careful that the structures are all released at the
+ * same time, as interrupts might otherwise get the wrong pointers.
+ *
+ * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
+ * lead to double frees or releasing memory still in use.
+ */
+
+int tty_release(struct inode *inode, struct file *filp)
+{
+       struct tty_struct *tty = file_tty(filp);
+       struct tty_struct *o_tty;
+       int     pty_master, tty_closing, o_tty_closing, do_sleep;
+       int     devpts;
+       int     idx;
+       char    buf[64];
+
+       if (tty_paranoia_check(tty, inode, "tty_release_dev"))
+               return 0;
+
+       tty_lock();
+       check_tty_count(tty, "tty_release_dev");
+
+       __tty_fasync(-1, filp, 0);
+
+       idx = tty->index;
+       pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+                     tty->driver->subtype == PTY_TYPE_MASTER);
+       devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
+       o_tty = tty->link;
+
+#ifdef TTY_PARANOIA_CHECK
+       if (idx < 0 || idx >= tty->driver->num) {
+               printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
+                                 "free (%s)\n", tty->name);
+               tty_unlock();
+               return 0;
+       }
+       if (!devpts) {
+               if (tty != tty->driver->ttys[idx]) {
+                       tty_unlock();
+                       printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
+                              "for (%s)\n", idx, tty->name);
+                       return 0;
+               }
+               if (tty->termios != tty->driver->termios[idx]) {
+                       tty_unlock();
+                       printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
+                              "for (%s)\n",
+                              idx, tty->name);
+                       return 0;
+               }
+       }
+#endif
+
+#ifdef TTY_DEBUG_HANGUP
+       printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...",
+              tty_name(tty, buf), tty->count);
+#endif
+
+#ifdef TTY_PARANOIA_CHECK
+       if (tty->driver->other &&
+            !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
+               if (o_tty != tty->driver->other->ttys[idx]) {
+                       tty_unlock();
+                       printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
+                                         "not o_tty for (%s)\n",
+                              idx, tty->name);
+                       return 0 ;
+               }
+               if (o_tty->termios != tty->driver->other->termios[idx]) {
+                       tty_unlock();
+                       printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
+                                         "not o_termios for (%s)\n",
+                              idx, tty->name);
+                       return 0;
+               }
+               if (o_tty->link != tty) {
+                       tty_unlock();
+                       printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
+                       return 0;
+               }
+       }
+#endif
+       if (tty->ops->close)
+               tty->ops->close(tty, filp);
+
+       tty_unlock();
+       /*
+        * Sanity check: if tty->count is going to zero, there shouldn't be
+        * any waiters on tty->read_wait or tty->write_wait.  We test the
+        * wait queues and kick everyone out _before_ actually starting to
+        * close.  This ensures that we won't block while releasing the tty
+        * structure.
+        *
+        * The test for the o_tty closing is necessary, since the master and
+        * slave sides may close in any order.  If the slave side closes out
+        * first, its count will be one, since the master side holds an open.
+        * Thus this test wouldn't be triggered at the time the slave closes,
+        * so we do it now.
+        *
+        * Note that it's possible for the tty to be opened again while we're
+        * flushing out waiters.  By recalculating the closing flags before
+        * each iteration we avoid any problems.
+        */
+       while (1) {
+               /* Guard against races with tty->count changes elsewhere and
+                  opens on /dev/tty */
+
+               mutex_lock(&tty_mutex);
+               tty_lock();
+               tty_closing = tty->count <= 1;
+               o_tty_closing = o_tty &&
+                       (o_tty->count <= (pty_master ? 1 : 0));
+               do_sleep = 0;
+
+               if (tty_closing) {
+                       if (waitqueue_active(&tty->read_wait)) {
+                               wake_up_poll(&tty->read_wait, POLLIN);
+                               do_sleep++;
+                       }
+                       if (waitqueue_active(&tty->write_wait)) {
+                               wake_up_poll(&tty->write_wait, POLLOUT);
+                               do_sleep++;
+                       }
+               }
+               if (o_tty_closing) {
+                       if (waitqueue_active(&o_tty->read_wait)) {
+                               wake_up_poll(&o_tty->read_wait, POLLIN);
+                               do_sleep++;
+                       }
+                       if (waitqueue_active(&o_tty->write_wait)) {
+                               wake_up_poll(&o_tty->write_wait, POLLOUT);
+                               do_sleep++;
+                       }
+               }
+               if (!do_sleep)
+                       break;
+
+               printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
+                                   "active!\n", tty_name(tty, buf));
+               tty_unlock();
+               mutex_unlock(&tty_mutex);
+               schedule();
+       }
+
+       /*
+        * The closing flags are now consistent with the open counts on
+        * both sides, and we've completed the last operation that could
+        * block, so it's safe to proceed with closing.
+        */
+       if (pty_master) {
+               if (--o_tty->count < 0) {
+                       printk(KERN_WARNING "tty_release_dev: bad pty slave count "
+                                           "(%d) for %s\n",
+                              o_tty->count, tty_name(o_tty, buf));
+                       o_tty->count = 0;
+               }
+       }
+       if (--tty->count < 0) {
+               printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
+                      tty->count, tty_name(tty, buf));
+               tty->count = 0;
+       }
+
+       /*
+        * We've decremented tty->count, so we need to remove this file
+        * descriptor off the tty->tty_files list; this serves two
+        * purposes:
+        *  - check_tty_count sees the correct number of file descriptors
+        *    associated with this tty.
+        *  - do_tty_hangup no longer sees this file descriptor as
+        *    something that needs to be handled for hangups.
+        */
+       tty_del_file(filp);
+
+       /*
+        * Perform some housekeeping before deciding whether to return.
+        *
+        * Set the TTY_CLOSING flag if this was the last open.  In the
+        * case of a pty we may have to wait around for the other side
+        * to close, and TTY_CLOSING makes sure we can't be reopened.
+        */
+       if (tty_closing)
+               set_bit(TTY_CLOSING, &tty->flags);
+       if (o_tty_closing)
+               set_bit(TTY_CLOSING, &o_tty->flags);
+
+       /*
+        * If _either_ side is closing, make sure there aren't any
+        * processes that still think tty or o_tty is their controlling
+        * tty.
+        */
+       if (tty_closing || o_tty_closing) {
+               read_lock(&tasklist_lock);
+               session_clear_tty(tty->session);
+               if (o_tty)
+                       session_clear_tty(o_tty->session);
+               read_unlock(&tasklist_lock);
+       }
+
+       mutex_unlock(&tty_mutex);
+
+       /* check whether both sides are closing ... */
+       if (!tty_closing || (o_tty && !o_tty_closing)) {
+               tty_unlock();
+               return 0;
+       }
+
+#ifdef TTY_DEBUG_HANGUP
+       printk(KERN_DEBUG "freeing tty structure...");
+#endif
+       /*
+        * Ask the line discipline code to release its structures
+        */
+       tty_ldisc_release(tty, o_tty);
+       /*
+        * The release_tty function takes care of the details of clearing
+        * the slots and preserving the termios structure.
+        */
+       release_tty(tty, idx);
+
+       /* Make this pty number available for reallocation */
+       if (devpts)
+               devpts_kill_index(inode, idx);
+       tty_unlock();
+       return 0;
+}
+
+/**
+ *     tty_open                -       open a tty device
+ *     @inode: inode of device file
+ *     @filp: file pointer to tty
+ *
+ *     tty_open and tty_release keep up the tty count that contains the
+ *     number of opens done on a tty. We cannot use the inode-count, as
+ *     different inodes might point to the same tty.
+ *
+ *     Open-counting is needed for pty masters, as well as for keeping
+ *     track of serial lines: DTR is dropped when the last close happens.
+ *     (This is not done solely through tty->count, now.  - Ted 1/27/92)
+ *
+ *     The termios state of a pty is reset on first open so that
+ *     settings don't persist across reuse.
+ *
+ *     Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work.
+ *              tty->count should protect the rest.
+ *              ->siglock protects ->signal/->sighand
+ */
+
+static int tty_open(struct inode *inode, struct file *filp)
+{
+       struct tty_struct *tty = NULL;
+       int noctty, retval;
+       struct tty_driver *driver;
+       int index;
+       dev_t device = inode->i_rdev;
+       unsigned saved_flags = filp->f_flags;
+
+       nonseekable_open(inode, filp);
+
+retry_open:
+       noctty = filp->f_flags & O_NOCTTY;
+       index  = -1;
+       retval = 0;
+
+       mutex_lock(&tty_mutex);
+       tty_lock();
+
+       if (device == MKDEV(TTYAUX_MAJOR, 0)) {
+               tty = get_current_tty();
+               if (!tty) {
+                       tty_unlock();
+                       mutex_unlock(&tty_mutex);
+                       return -ENXIO;
+               }
+               driver = tty_driver_kref_get(tty->driver);
+               index = tty->index;
+               filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
+               /* noctty = 1; */
+               /* FIXME: Should we take a driver reference ? */
+               tty_kref_put(tty);
+               goto got_driver;
+       }
+#ifdef CONFIG_VT
+       if (device == MKDEV(TTY_MAJOR, 0)) {
+               extern struct tty_driver *console_driver;
+               driver = tty_driver_kref_get(console_driver);
+               index = fg_console;
+               noctty = 1;
+               goto got_driver;
+       }
+#endif
+       if (device == MKDEV(TTYAUX_MAJOR, 1)) {
+               struct tty_driver *console_driver = console_device(&index);
+               if (console_driver) {
+                       driver = tty_driver_kref_get(console_driver);
+                       if (driver) {
+                               /* Don't let /dev/console block */
+                               filp->f_flags |= O_NONBLOCK;
+                               noctty = 1;
+                               goto got_driver;
+                       }
+               }
+               tty_unlock();
+               mutex_unlock(&tty_mutex);
+               return -ENODEV;
+       }
+
+       driver = get_tty_driver(device, &index);
+       if (!driver) {
+               tty_unlock();
+               mutex_unlock(&tty_mutex);
+               return -ENODEV;
+       }
+got_driver:
+       if (!tty) {
+               /* check whether we're reopening an existing tty */
+               tty = tty_driver_lookup_tty(driver, inode, index);
+
+               if (IS_ERR(tty)) {
+                       tty_unlock();
+                       mutex_unlock(&tty_mutex);
+                       return PTR_ERR(tty);
+               }
+       }
+
+       if (tty) {
+               retval = tty_reopen(tty);
+               if (retval)
+                       tty = ERR_PTR(retval);
+       } else
+               tty = tty_init_dev(driver, index, 0);
+
+       mutex_unlock(&tty_mutex);
+       tty_driver_kref_put(driver);
+       if (IS_ERR(tty)) {
+               tty_unlock();
+               return PTR_ERR(tty);
+       }
+
+       retval = tty_add_file(tty, filp);
+       if (retval) {
+               tty_unlock();
+               return retval;
+       }
+
+       check_tty_count(tty, "tty_open");
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_MASTER)
+               noctty = 1;
+#ifdef TTY_DEBUG_HANGUP
+       printk(KERN_DEBUG "opening %s...", tty->name);
+#endif
+       if (!retval) {
+               if (tty->ops->open)
+                       retval = tty->ops->open(tty, filp);
+               else
+                       retval = -ENODEV;
+       }
+       filp->f_flags = saved_flags;
+
+       if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) &&
+                                               !capable(CAP_SYS_ADMIN))
+               retval = -EBUSY;
+
+       if (retval) {
+#ifdef TTY_DEBUG_HANGUP
+               printk(KERN_DEBUG "error %d in opening %s...", retval,
+                      tty->name);
+#endif
+               tty_unlock(); /* need to call tty_release without BTM */
+               tty_release(inode, filp);
+               if (retval != -ERESTARTSYS)
+                       return retval;
+
+               if (signal_pending(current))
+                       return retval;
+
+               schedule();
+               /*
+                * Need to reset f_op in case a hangup happened.
+                */
+               tty_lock();
+               if (filp->f_op == &hung_up_tty_fops)
+                       filp->f_op = &tty_fops;
+               tty_unlock();
+               goto retry_open;
+       }
+       tty_unlock();
+
+
+       mutex_lock(&tty_mutex);
+       tty_lock();
+       spin_lock_irq(&current->sighand->siglock);
+       if (!noctty &&
+           current->signal->leader &&
+           !current->signal->tty &&
+           tty->session == NULL)
+               __proc_set_tty(current, tty);
+       spin_unlock_irq(&current->sighand->siglock);
+       tty_unlock();
+       mutex_unlock(&tty_mutex);
+       return 0;
+}
+
+
+
+/**
+ *     tty_poll        -       check tty status
+ *     @filp: file being polled
+ *     @wait: poll wait structures to update
+ *
+ *     Call the line discipline polling method to obtain the poll
+ *     status of the device.
+ *
+ *     Locking: locks called line discipline but ldisc poll method
+ *     may be re-entered freely by other callers.
+ */
+
+static unsigned int tty_poll(struct file *filp, poll_table *wait)
+{
+       struct tty_struct *tty = file_tty(filp);
+       struct tty_ldisc *ld;
+       int ret = 0;
+
+       if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll"))
+               return 0;
+
+       ld = tty_ldisc_ref_wait(tty);
+       if (ld->ops->poll)
+               ret = (ld->ops->poll)(tty, filp, wait);
+       tty_ldisc_deref(ld);
+       return ret;
+}
+
+static int __tty_fasync(int fd, struct file *filp, int on)
+{
+       struct tty_struct *tty = file_tty(filp);
+       unsigned long flags;
+       int retval = 0;
+
+       if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync"))
+               goto out;
+
+       retval = fasync_helper(fd, filp, on, &tty->fasync);
+       if (retval <= 0)
+               goto out;
+
+       if (on) {
+               enum pid_type type;
+               struct pid *pid;
+               if (!waitqueue_active(&tty->read_wait))
+                       tty->minimum_to_wake = 1;
+               spin_lock_irqsave(&tty->ctrl_lock, flags);
+               if (tty->pgrp) {
+                       pid = tty->pgrp;
+                       type = PIDTYPE_PGID;
+               } else {
+                       pid = task_pid(current);
+                       type = PIDTYPE_PID;
+               }
+               get_pid(pid);
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               retval = __f_setown(filp, pid, type, 0);
+               put_pid(pid);
+               if (retval)
+                       goto out;
+       } else {
+               if (!tty->fasync && !waitqueue_active(&tty->read_wait))
+                       tty->minimum_to_wake = N_TTY_BUF_SIZE;
+       }
+       retval = 0;
+out:
+       return retval;
+}
+
+static int tty_fasync(int fd, struct file *filp, int on)
+{
+       int retval;
+       tty_lock();
+       retval = __tty_fasync(fd, filp, on);
+       tty_unlock();
+       return retval;
+}
+
+/**
+ *     tiocsti                 -       fake input character
+ *     @tty: tty to fake input into
+ *     @p: pointer to character
+ *
+ *     Fake input to a tty device. Does the necessary locking and
+ *     input management.
+ *
+ *     FIXME: does not honour flow control ??
+ *
+ *     Locking:
+ *             Called functions take tty_ldisc_lock
+ *             current->signal->tty check is safe without locks
+ *
+ *     FIXME: may race normal receive processing
+ */
+
+static int tiocsti(struct tty_struct *tty, char __user *p)
+{
+       char ch, mbz = 0;
+       struct tty_ldisc *ld;
+
+       if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (get_user(ch, p))
+               return -EFAULT;
+       tty_audit_tiocsti(tty, ch);
+       ld = tty_ldisc_ref_wait(tty);
+       ld->ops->receive_buf(tty, &ch, &mbz, 1);
+       tty_ldisc_deref(ld);
+       return 0;
+}
+
+/**
+ *     tiocgwinsz              -       implement window query ioctl
+ *     @tty; tty
+ *     @arg: user buffer for result
+ *
+ *     Copies the kernel idea of the window size into the user buffer.
+ *
+ *     Locking: tty->termios_mutex is taken to ensure the winsize data
+ *             is consistent.
+ */
+
+static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
+{
+       int err;
+
+       mutex_lock(&tty->termios_mutex);
+       err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
+       mutex_unlock(&tty->termios_mutex);
+
+       return err ? -EFAULT: 0;
+}
+
+/**
+ *     tty_do_resize           -       resize event
+ *     @tty: tty being resized
+ *     @rows: rows (character)
+ *     @cols: cols (character)
+ *
+ *     Update the termios variables and send the necessary signals to
+ *     peform a terminal resize correctly
+ */
+
+int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
+{
+       struct pid *pgrp;
+       unsigned long flags;
+
+       /* Lock the tty */
+       mutex_lock(&tty->termios_mutex);
+       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
+               goto done;
+       /* Get the PID values and reference them so we can
+          avoid holding the tty ctrl lock while sending signals */
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       pgrp = get_pid(tty->pgrp);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+       if (pgrp)
+               kill_pgrp(pgrp, SIGWINCH, 1);
+       put_pid(pgrp);
+
+       tty->winsize = *ws;
+done:
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+
+/**
+ *     tiocswinsz              -       implement window size set ioctl
+ *     @tty; tty side of tty
+ *     @arg: user buffer for result
+ *
+ *     Copies the user idea of the window size to the kernel. Traditionally
+ *     this is just advisory information but for the Linux console it
+ *     actually has driver level meaning and triggers a VC resize.
+ *
+ *     Locking:
+ *             Driver dependant. The default do_resize method takes the
+ *     tty termios mutex and ctrl_lock. The console takes its own lock
+ *     then calls into the default method.
+ */
+
+static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg)
+{
+       struct winsize tmp_ws;
+       if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
+               return -EFAULT;
+
+       if (tty->ops->resize)
+               return tty->ops->resize(tty, &tmp_ws);
+       else
+               return tty_do_resize(tty, &tmp_ws);
+}
+
+/**
+ *     tioccons        -       allow admin to move logical console
+ *     @file: the file to become console
+ *
+ *     Allow the adminstrator to move the redirected console device
+ *
+ *     Locking: uses redirect_lock to guard the redirect information
+ */
+
+static int tioccons(struct file *file)
+{
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (file->f_op->write == redirected_tty_write) {
+               struct file *f;
+               spin_lock(&redirect_lock);
+               f = redirect;
+               redirect = NULL;
+               spin_unlock(&redirect_lock);
+               if (f)
+                       fput(f);
+               return 0;
+       }
+       spin_lock(&redirect_lock);
+       if (redirect) {
+               spin_unlock(&redirect_lock);
+               return -EBUSY;
+       }
+       get_file(file);
+       redirect = file;
+       spin_unlock(&redirect_lock);
+       return 0;
+}
+
+/**
+ *     fionbio         -       non blocking ioctl
+ *     @file: file to set blocking value
+ *     @p: user parameter
+ *
+ *     Historical tty interfaces had a blocking control ioctl before
+ *     the generic functionality existed. This piece of history is preserved
+ *     in the expected tty API of posix OS's.
+ *
+ *     Locking: none, the open file handle ensures it won't go away.
+ */
+
+static int fionbio(struct file *file, int __user *p)
+{
+       int nonblock;
+
+       if (get_user(nonblock, p))
+               return -EFAULT;
+
+       spin_lock(&file->f_lock);
+       if (nonblock)
+               file->f_flags |= O_NONBLOCK;
+       else
+               file->f_flags &= ~O_NONBLOCK;
+       spin_unlock(&file->f_lock);
+       return 0;
+}
+
+/**
+ *     tiocsctty       -       set controlling tty
+ *     @tty: tty structure
+ *     @arg: user argument
+ *
+ *     This ioctl is used to manage job control. It permits a session
+ *     leader to set this tty as the controlling tty for the session.
+ *
+ *     Locking:
+ *             Takes tty_mutex() to protect tty instance
+ *             Takes tasklist_lock internally to walk sessions
+ *             Takes ->siglock() when updating signal->tty
+ */
+
+static int tiocsctty(struct tty_struct *tty, int arg)
+{
+       int ret = 0;
+       if (current->signal->leader && (task_session(current) == tty->session))
+               return ret;
+
+       mutex_lock(&tty_mutex);
+       /*
+        * The process must be a session leader and
+        * not have a controlling tty already.
+        */
+       if (!current->signal->leader || current->signal->tty) {
+               ret = -EPERM;
+               goto unlock;
+       }
+
+       if (tty->session) {
+               /*
+                * This tty is already the controlling
+                * tty for another session group!
+                */
+               if (arg == 1 && capable(CAP_SYS_ADMIN)) {
+                       /*
+                        * Steal it away
+                        */
+                       read_lock(&tasklist_lock);
+                       session_clear_tty(tty->session);
+                       read_unlock(&tasklist_lock);
+               } else {
+                       ret = -EPERM;
+                       goto unlock;
+               }
+       }
+       proc_set_tty(current, tty);
+unlock:
+       mutex_unlock(&tty_mutex);
+       return ret;
+}
+
+/**
+ *     tty_get_pgrp    -       return a ref counted pgrp pid
+ *     @tty: tty to read
+ *
+ *     Returns a refcounted instance of the pid struct for the process
+ *     group controlling the tty.
+ */
+
+struct pid *tty_get_pgrp(struct tty_struct *tty)
+{
+       unsigned long flags;
+       struct pid *pgrp;
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       pgrp = get_pid(tty->pgrp);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+       return pgrp;
+}
+EXPORT_SYMBOL_GPL(tty_get_pgrp);
+
+/**
+ *     tiocgpgrp               -       get process group
+ *     @tty: tty passed by user
+ *     @real_tty: tty side of the tty pased by the user if a pty else the tty
+ *     @p: returned pid
+ *
+ *     Obtain the process group of the tty. If there is no process group
+ *     return an error.
+ *
+ *     Locking: none. Reference to current->signal->tty is safe.
+ */
+
+static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
+{
+       struct pid *pid;
+       int ret;
+       /*
+        * (tty == real_tty) is a cheap way of
+        * testing if the tty is NOT a master pty.
+        */
+       if (tty == real_tty && current->signal->tty != real_tty)
+               return -ENOTTY;
+       pid = tty_get_pgrp(real_tty);
+       ret =  put_user(pid_vnr(pid), p);
+       put_pid(pid);
+       return ret;
+}
+
+/**
+ *     tiocspgrp               -       attempt to set process group
+ *     @tty: tty passed by user
+ *     @real_tty: tty side device matching tty passed by user
+ *     @p: pid pointer
+ *
+ *     Set the process group of the tty to the session passed. Only
+ *     permitted where the tty session is our session.
+ *
+ *     Locking: RCU, ctrl lock
+ */
+
+static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
+{
+       struct pid *pgrp;
+       pid_t pgrp_nr;
+       int retval = tty_check_change(real_tty);
+       unsigned long flags;
+
+       if (retval == -EIO)
+               return -ENOTTY;
+       if (retval)
+               return retval;
+       if (!current->signal->tty ||
+           (current->signal->tty != real_tty) ||
+           (real_tty->session != task_session(current)))
+               return -ENOTTY;
+       if (get_user(pgrp_nr, p))
+               return -EFAULT;
+       if (pgrp_nr < 0)
+               return -EINVAL;
+       rcu_read_lock();
+       pgrp = find_vpid(pgrp_nr);
+       retval = -ESRCH;
+       if (!pgrp)
+               goto out_unlock;
+       retval = -EPERM;
+       if (session_of_pgrp(pgrp) != task_session(current))
+               goto out_unlock;
+       retval = 0;
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       put_pid(real_tty->pgrp);
+       real_tty->pgrp = get_pid(pgrp);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+out_unlock:
+       rcu_read_unlock();
+       return retval;
+}
+
+/**
+ *     tiocgsid                -       get session id
+ *     @tty: tty passed by user
+ *     @real_tty: tty side of the tty pased by the user if a pty else the tty
+ *     @p: pointer to returned session id
+ *
+ *     Obtain the session id of the tty. If there is no session
+ *     return an error.
+ *
+ *     Locking: none. Reference to current->signal->tty is safe.
+ */
+
+static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
+{
+       /*
+        * (tty == real_tty) is a cheap way of
+        * testing if the tty is NOT a master pty.
+       */
+       if (tty == real_tty && current->signal->tty != real_tty)
+               return -ENOTTY;
+       if (!real_tty->session)
+               return -ENOTTY;
+       return put_user(pid_vnr(real_tty->session), p);
+}
+
+/**
+ *     tiocsetd        -       set line discipline
+ *     @tty: tty device
+ *     @p: pointer to user data
+ *
+ *     Set the line discipline according to user request.
+ *
+ *     Locking: see tty_set_ldisc, this function is just a helper
+ */
+
+static int tiocsetd(struct tty_struct *tty, int __user *p)
+{
+       int ldisc;
+       int ret;
+
+       if (get_user(ldisc, p))
+               return -EFAULT;
+
+       ret = tty_set_ldisc(tty, ldisc);
+
+       return ret;
+}
+
+/**
+ *     send_break      -       performed time break
+ *     @tty: device to break on
+ *     @duration: timeout in mS
+ *
+ *     Perform a timed break on hardware that lacks its own driver level
+ *     timed break functionality.
+ *
+ *     Locking:
+ *             atomic_write_lock serializes
+ *
+ */
+
+static int send_break(struct tty_struct *tty, unsigned int duration)
+{
+       int retval;
+
+       if (tty->ops->break_ctl == NULL)
+               return 0;
+
+       if (tty->driver->flags & TTY_DRIVER_HARDWARE_BREAK)
+               retval = tty->ops->break_ctl(tty, duration);
+       else {
+               /* Do the work ourselves */
+               if (tty_write_lock(tty, 0) < 0)
+                       return -EINTR;
+               retval = tty->ops->break_ctl(tty, -1);
+               if (retval)
+                       goto out;
+               if (!signal_pending(current))
+                       msleep_interruptible(duration);
+               retval = tty->ops->break_ctl(tty, 0);
+out:
+               tty_write_unlock(tty);
+               if (signal_pending(current))
+                       retval = -EINTR;
+       }
+       return retval;
+}
+
+/**
+ *     tty_tiocmget            -       get modem status
+ *     @tty: tty device
+ *     @file: user file pointer
+ *     @p: pointer to result
+ *
+ *     Obtain the modem status bits from the tty driver if the feature
+ *     is supported. Return -EINVAL if it is not available.
+ *
+ *     Locking: none (up to the driver)
+ */
+
+static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p)
+{
+       int retval = -EINVAL;
+
+       if (tty->ops->tiocmget) {
+               retval = tty->ops->tiocmget(tty, file);
+
+               if (retval >= 0)
+                       retval = put_user(retval, p);
+       }
+       return retval;
+}
+
+/**
+ *     tty_tiocmset            -       set modem status
+ *     @tty: tty device
+ *     @file: user file pointer
+ *     @cmd: command - clear bits, set bits or set all
+ *     @p: pointer to desired bits
+ *
+ *     Set the modem status bits from the tty driver if the feature
+ *     is supported. Return -EINVAL if it is not available.
+ *
+ *     Locking: none (up to the driver)
+ */
+
+static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd,
+            unsigned __user *p)
+{
+       int retval;
+       unsigned int set, clear, val;
+
+       if (tty->ops->tiocmset == NULL)
+               return -EINVAL;
+
+       retval = get_user(val, p);
+       if (retval)
+               return retval;
+       set = clear = 0;
+       switch (cmd) {
+       case TIOCMBIS:
+               set = val;
+               break;
+       case TIOCMBIC:
+               clear = val;
+               break;
+       case TIOCMSET:
+               set = val;
+               clear = ~val;
+               break;
+       }
+       set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
+       clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
+       return tty->ops->tiocmset(tty, file, set, clear);
+}
+
+static int tty_tiocgicount(struct tty_struct *tty, void __user *arg)
+{
+       int retval = -EINVAL;
+       struct serial_icounter_struct icount;
+       memset(&icount, 0, sizeof(icount));
+       if (tty->ops->get_icount)
+               retval = tty->ops->get_icount(tty, &icount);
+       if (retval != 0)
+               return retval;
+       if (copy_to_user(arg, &icount, sizeof(icount)))
+               return -EFAULT;
+       return 0;
+}
+
+struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
+{
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_MASTER)
+               tty = tty->link;
+       return tty;
+}
+EXPORT_SYMBOL(tty_pair_get_tty);
+
+struct tty_struct *tty_pair_get_pty(struct tty_struct *tty)
+{
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_MASTER)
+           return tty;
+       return tty->link;
+}
+EXPORT_SYMBOL(tty_pair_get_pty);
+
+/*
+ * Split this up, as gcc can choke on it otherwise..
+ */
+long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct tty_struct *tty = file_tty(file);
+       struct tty_struct *real_tty;
+       void __user *p = (void __user *)arg;
+       int retval;
+       struct tty_ldisc *ld;
+       struct inode *inode = file->f_dentry->d_inode;
+
+       if (tty_paranoia_check(tty, inode, "tty_ioctl"))
+               return -EINVAL;
+
+       real_tty = tty_pair_get_tty(tty);
+
+       /*
+        * Factor out some common prep work
+        */
+       switch (cmd) {
+       case TIOCSETD:
+       case TIOCSBRK:
+       case TIOCCBRK:
+       case TCSBRK:
+       case TCSBRKP:
+               retval = tty_check_change(tty);
+               if (retval)
+                       return retval;
+               if (cmd != TIOCCBRK) {
+                       tty_wait_until_sent(tty, 0);
+                       if (signal_pending(current))
+                               return -EINTR;
+               }
+               break;
+       }
+
+       /*
+        *      Now do the stuff.
+        */
+       switch (cmd) {
+       case TIOCSTI:
+               return tiocsti(tty, p);
+       case TIOCGWINSZ:
+               return tiocgwinsz(real_tty, p);
+       case TIOCSWINSZ:
+               return tiocswinsz(real_tty, p);
+       case TIOCCONS:
+               return real_tty != tty ? -EINVAL : tioccons(file);
+       case FIONBIO:
+               return fionbio(file, p);
+       case TIOCEXCL:
+               set_bit(TTY_EXCLUSIVE, &tty->flags);
+               return 0;
+       case TIOCNXCL:
+               clear_bit(TTY_EXCLUSIVE, &tty->flags);
+               return 0;
+       case TIOCNOTTY:
+               if (current->signal->tty != tty)
+                       return -ENOTTY;
+               no_tty();
+               return 0;
+       case TIOCSCTTY:
+               return tiocsctty(tty, arg);
+       case TIOCGPGRP:
+               return tiocgpgrp(tty, real_tty, p);
+       case TIOCSPGRP:
+               return tiocspgrp(tty, real_tty, p);
+       case TIOCGSID:
+               return tiocgsid(tty, real_tty, p);
+       case TIOCGETD:
+               return put_user(tty->ldisc->ops->num, (int __user *)p);
+       case TIOCSETD:
+               return tiocsetd(tty, p);
+       /*
+        * Break handling
+        */
+       case TIOCSBRK:  /* Turn break on, unconditionally */
+               if (tty->ops->break_ctl)
+                       return tty->ops->break_ctl(tty, -1);
+               return 0;
+       case TIOCCBRK:  /* Turn break off, unconditionally */
+               if (tty->ops->break_ctl)
+                       return tty->ops->break_ctl(tty, 0);
+               return 0;
+       case TCSBRK:   /* SVID version: non-zero arg --> no break */
+               /* non-zero arg means wait for all output data
+                * to be sent (performed above) but don't send break.
+                * This is used by the tcdrain() termios function.
+                */
+               if (!arg)
+                       return send_break(tty, 250);
+               return 0;
+       case TCSBRKP:   /* support for POSIX tcsendbreak() */
+               return send_break(tty, arg ? arg*100 : 250);
+
+       case TIOCMGET:
+               return tty_tiocmget(tty, file, p);
+       case TIOCMSET:
+       case TIOCMBIC:
+       case TIOCMBIS:
+               return tty_tiocmset(tty, file, cmd, p);
+       case TIOCGICOUNT:
+               retval = tty_tiocgicount(tty, p);
+               /* For the moment allow fall through to the old method */
+               if (retval != -EINVAL)
+                       return retval;
+               break;
+       case TCFLSH:
+               switch (arg) {
+               case TCIFLUSH:
+               case TCIOFLUSH:
+               /* flush tty buffer and allow ldisc to process ioctl */
+                       tty_buffer_flush(tty);
+                       break;
+               }
+               break;
+       }
+       if (tty->ops->ioctl) {
+               retval = (tty->ops->ioctl)(tty, file, cmd, arg);
+               if (retval != -ENOIOCTLCMD)
+                       return retval;
+       }
+       ld = tty_ldisc_ref_wait(tty);
+       retval = -EINVAL;
+       if (ld->ops->ioctl) {
+               retval = ld->ops->ioctl(tty, file, cmd, arg);
+               if (retval == -ENOIOCTLCMD)
+                       retval = -EINVAL;
+       }
+       tty_ldisc_deref(ld);
+       return retval;
+}
+
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct tty_struct *tty = file_tty(file);
+       struct tty_ldisc *ld;
+       int retval = -ENOIOCTLCMD;
+
+       if (tty_paranoia_check(tty, inode, "tty_ioctl"))
+               return -EINVAL;
+
+       if (tty->ops->compat_ioctl) {
+               retval = (tty->ops->compat_ioctl)(tty, file, cmd, arg);
+               if (retval != -ENOIOCTLCMD)
+                       return retval;
+       }
+
+       ld = tty_ldisc_ref_wait(tty);
+       if (ld->ops->compat_ioctl)
+               retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
+       tty_ldisc_deref(ld);
+
+       return retval;
+}
+#endif
+
+/*
+ * This implements the "Secure Attention Key" ---  the idea is to
+ * prevent trojan horses by killing all processes associated with this
+ * tty when the user hits the "Secure Attention Key".  Required for
+ * super-paranoid applications --- see the Orange Book for more details.
+ *
+ * This code could be nicer; ideally it should send a HUP, wait a few
+ * seconds, then send a INT, and then a KILL signal.  But you then
+ * have to coordinate with the init process, since all processes associated
+ * with the current tty must be dead before the new getty is allowed
+ * to spawn.
+ *
+ * Now, if it would be correct ;-/ The current code has a nasty hole -
+ * it doesn't catch files in flight. We may send the descriptor to ourselves
+ * via AF_UNIX socket, close it and later fetch from socket. FIXME.
+ *
+ * Nasty bug: do_SAK is being called in interrupt context.  This can
+ * deadlock.  We punt it up to process context.  AKPM - 16Mar2001
+ */
+void __do_SAK(struct tty_struct *tty)
+{
+#ifdef TTY_SOFT_SAK
+       tty_hangup(tty);
+#else
+       struct task_struct *g, *p;
+       struct pid *session;
+       int             i;
+       struct file     *filp;
+       struct fdtable *fdt;
+
+       if (!tty)
+               return;
+       session = tty->session;
+
+       tty_ldisc_flush(tty);
+
+       tty_driver_flush_buffer(tty);
+
+       read_lock(&tasklist_lock);
+       /* Kill the entire session */
+       do_each_pid_task(session, PIDTYPE_SID, p) {
+               printk(KERN_NOTICE "SAK: killed process %d"
+                       " (%s): task_session(p)==tty->session\n",
+                       task_pid_nr(p), p->comm);
+               send_sig(SIGKILL, p, 1);
+       } while_each_pid_task(session, PIDTYPE_SID, p);
+       /* Now kill any processes that happen to have the
+        * tty open.
+        */
+       do_each_thread(g, p) {
+               if (p->signal->tty == tty) {
+                       printk(KERN_NOTICE "SAK: killed process %d"
+                           " (%s): task_session(p)==tty->session\n",
+                           task_pid_nr(p), p->comm);
+                       send_sig(SIGKILL, p, 1);
+                       continue;
+               }
+               task_lock(p);
+               if (p->files) {
+                       /*
+                        * We don't take a ref to the file, so we must
+                        * hold ->file_lock instead.
+                        */
+                       spin_lock(&p->files->file_lock);
+                       fdt = files_fdtable(p->files);
+                       for (i = 0; i < fdt->max_fds; i++) {
+                               filp = fcheck_files(p->files, i);
+                               if (!filp)
+                                       continue;
+                               if (filp->f_op->read == tty_read &&
+                                   file_tty(filp) == tty) {
+                                       printk(KERN_NOTICE "SAK: killed process %d"
+                                           " (%s): fd#%d opened to the tty\n",
+                                           task_pid_nr(p), p->comm, i);
+                                       force_sig(SIGKILL, p);
+                                       break;
+                               }
+                       }
+                       spin_unlock(&p->files->file_lock);
+               }
+               task_unlock(p);
+       } while_each_thread(g, p);
+       read_unlock(&tasklist_lock);
+#endif
+}
+
+static void do_SAK_work(struct work_struct *work)
+{
+       struct tty_struct *tty =
+               container_of(work, struct tty_struct, SAK_work);
+       __do_SAK(tty);
+}
+
+/*
+ * The tq handling here is a little racy - tty->SAK_work may already be queued.
+ * Fortunately we don't need to worry, because if ->SAK_work is already queued,
+ * the values which we write to it will be identical to the values which it
+ * already has. --akpm
+ */
+void do_SAK(struct tty_struct *tty)
+{
+       if (!tty)
+               return;
+       schedule_work(&tty->SAK_work);
+}
+
+EXPORT_SYMBOL(do_SAK);
+
+static int dev_match_devt(struct device *dev, void *data)
+{
+       dev_t *devt = data;
+       return dev->devt == *devt;
+}
+
+/* Must put_device() after it's unused! */
+static struct device *tty_get_device(struct tty_struct *tty)
+{
+       dev_t devt = tty_devnum(tty);
+       return class_find_device(tty_class, NULL, &devt, dev_match_devt);
+}
+
+
+/**
+ *     initialize_tty_struct
+ *     @tty: tty to initialize
+ *
+ *     This subroutine initializes a tty structure that has been newly
+ *     allocated.
+ *
+ *     Locking: none - tty in question must not be exposed at this point
+ */
+
+void initialize_tty_struct(struct tty_struct *tty,
+               struct tty_driver *driver, int idx)
+{
+       memset(tty, 0, sizeof(struct tty_struct));
+       kref_init(&tty->kref);
+       tty->magic = TTY_MAGIC;
+       tty_ldisc_init(tty);
+       tty->session = NULL;
+       tty->pgrp = NULL;
+       tty->overrun_time = jiffies;
+       tty->buf.head = tty->buf.tail = NULL;
+       tty_buffer_init(tty);
+       mutex_init(&tty->termios_mutex);
+       mutex_init(&tty->ldisc_mutex);
+       init_waitqueue_head(&tty->write_wait);
+       init_waitqueue_head(&tty->read_wait);
+       INIT_WORK(&tty->hangup_work, do_tty_hangup);
+       mutex_init(&tty->atomic_read_lock);
+       mutex_init(&tty->atomic_write_lock);
+       mutex_init(&tty->output_lock);
+       mutex_init(&tty->echo_lock);
+       spin_lock_init(&tty->read_lock);
+       spin_lock_init(&tty->ctrl_lock);
+       INIT_LIST_HEAD(&tty->tty_files);
+       INIT_WORK(&tty->SAK_work, do_SAK_work);
+
+       tty->driver = driver;
+       tty->ops = driver->ops;
+       tty->index = idx;
+       tty_line_name(driver, idx, tty->name);
+       tty->dev = tty_get_device(tty);
+}
+
+/**
+ *     tty_put_char    -       write one character to a tty
+ *     @tty: tty
+ *     @ch: character
+ *
+ *     Write one byte to the tty using the provided put_char method
+ *     if present. Returns the number of characters successfully output.
+ *
+ *     Note: the specific put_char operation in the driver layer may go
+ *     away soon. Don't call it directly, use this method
+ */
+
+int tty_put_char(struct tty_struct *tty, unsigned char ch)
+{
+       if (tty->ops->put_char)
+               return tty->ops->put_char(tty, ch);
+       return tty->ops->write(tty, &ch, 1);
+}
+EXPORT_SYMBOL_GPL(tty_put_char);
+
+struct class *tty_class;
+
+/**
+ *     tty_register_device - register a tty device
+ *     @driver: the tty driver that describes the tty device
+ *     @index: the index in the tty driver for this tty device
+ *     @device: a struct device that is associated with this tty device.
+ *             This field is optional, if there is no known struct device
+ *             for this tty device it can be set to NULL safely.
+ *
+ *     Returns a pointer to the struct device for this tty device
+ *     (or ERR_PTR(-EFOO) on error).
+ *
+ *     This call is required to be made to register an individual tty device
+ *     if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set.  If
+ *     that bit is not set, this function should not be called by a tty
+ *     driver.
+ *
+ *     Locking: ??
+ */
+
+struct device *tty_register_device(struct tty_driver *driver, unsigned index,
+                                  struct device *device)
+{
+       char name[64];
+       dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
+
+       if (index >= driver->num) {
+               printk(KERN_ERR "Attempt to register invalid tty line number "
+                      " (%d).\n", index);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (driver->type == TTY_DRIVER_TYPE_PTY)
+               pty_line_name(driver, index, name);
+       else
+               tty_line_name(driver, index, name);
+
+       return device_create(tty_class, device, dev, NULL, name);
+}
+EXPORT_SYMBOL(tty_register_device);
+
+/**
+ *     tty_unregister_device - unregister a tty device
+ *     @driver: the tty driver that describes the tty device
+ *     @index: the index in the tty driver for this tty device
+ *
+ *     If a tty device is registered with a call to tty_register_device() then
+ *     this function must be called when the tty device is gone.
+ *
+ *     Locking: ??
+ */
+
+void tty_unregister_device(struct tty_driver *driver, unsigned index)
+{
+       device_destroy(tty_class,
+               MKDEV(driver->major, driver->minor_start) + index);
+}
+EXPORT_SYMBOL(tty_unregister_device);
+
+struct tty_driver *alloc_tty_driver(int lines)
+{
+       struct tty_driver *driver;
+
+       driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
+       if (driver) {
+               kref_init(&driver->kref);
+               driver->magic = TTY_DRIVER_MAGIC;
+               driver->num = lines;
+               /* later we'll move allocation of tables here */
+       }
+       return driver;
+}
+EXPORT_SYMBOL(alloc_tty_driver);
+
+static void destruct_tty_driver(struct kref *kref)
+{
+       struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
+       int i;
+       struct ktermios *tp;
+       void *p;
+
+       if (driver->flags & TTY_DRIVER_INSTALLED) {
+               /*
+                * Free the termios and termios_locked structures because
+                * we don't want to get memory leaks when modular tty
+                * drivers are removed from the kernel.
+                */
+               for (i = 0; i < driver->num; i++) {
+                       tp = driver->termios[i];
+                       if (tp) {
+                               driver->termios[i] = NULL;
+                               kfree(tp);
+                       }
+                       if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
+                               tty_unregister_device(driver, i);
+               }
+               p = driver->ttys;
+               proc_tty_unregister_driver(driver);
+               driver->ttys = NULL;
+               driver->termios = NULL;
+               kfree(p);
+               cdev_del(&driver->cdev);
+       }
+       kfree(driver);
+}
+
+void tty_driver_kref_put(struct tty_driver *driver)
+{
+       kref_put(&driver->kref, destruct_tty_driver);
+}
+EXPORT_SYMBOL(tty_driver_kref_put);
+
+void tty_set_operations(struct tty_driver *driver,
+                       const struct tty_operations *op)
+{
+       driver->ops = op;
+};
+EXPORT_SYMBOL(tty_set_operations);
+
+void put_tty_driver(struct tty_driver *d)
+{
+       tty_driver_kref_put(d);
+}
+EXPORT_SYMBOL(put_tty_driver);
+
+/*
+ * Called by a tty driver to register itself.
+ */
+int tty_register_driver(struct tty_driver *driver)
+{
+       int error;
+       int i;
+       dev_t dev;
+       void **p = NULL;
+       struct device *d;
+
+       if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
+               p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
+               if (!p)
+                       return -ENOMEM;
+       }
+
+       if (!driver->major) {
+               error = alloc_chrdev_region(&dev, driver->minor_start,
+                                               driver->num, driver->name);
+               if (!error) {
+                       driver->major = MAJOR(dev);
+                       driver->minor_start = MINOR(dev);
+               }
+       } else {
+               dev = MKDEV(driver->major, driver->minor_start);
+               error = register_chrdev_region(dev, driver->num, driver->name);
+       }
+       if (error < 0) {
+               kfree(p);
+               return error;
+       }
+
+       if (p) {
+               driver->ttys = (struct tty_struct **)p;
+               driver->termios = (struct ktermios **)(p + driver->num);
+       } else {
+               driver->ttys = NULL;
+               driver->termios = NULL;
+       }
+
+       cdev_init(&driver->cdev, &tty_fops);
+       driver->cdev.owner = driver->owner;
+       error = cdev_add(&driver->cdev, dev, driver->num);
+       if (error) {
+               unregister_chrdev_region(dev, driver->num);
+               driver->ttys = NULL;
+               driver->termios = NULL;
+               kfree(p);
+               return error;
+       }
+
+       mutex_lock(&tty_mutex);
+       list_add(&driver->tty_drivers, &tty_drivers);
+       mutex_unlock(&tty_mutex);
+
+       if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
+               for (i = 0; i < driver->num; i++) {
+                       d = tty_register_device(driver, i, NULL);
+                       if (IS_ERR(d)) {
+                               error = PTR_ERR(d);
+                               goto err;
+                       }
+               }
+       }
+       proc_tty_register_driver(driver);
+       driver->flags |= TTY_DRIVER_INSTALLED;
+       return 0;
+
+err:
+       for (i--; i >= 0; i--)
+               tty_unregister_device(driver, i);
+
+       mutex_lock(&tty_mutex);
+       list_del(&driver->tty_drivers);
+       mutex_unlock(&tty_mutex);
+
+       unregister_chrdev_region(dev, driver->num);
+       driver->ttys = NULL;
+       driver->termios = NULL;
+       kfree(p);
+       return error;
+}
+
+EXPORT_SYMBOL(tty_register_driver);
+
+/*
+ * Called by a tty driver to unregister itself.
+ */
+int tty_unregister_driver(struct tty_driver *driver)
+{
+#if 0
+       /* FIXME */
+       if (driver->refcount)
+               return -EBUSY;
+#endif
+       unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
+                               driver->num);
+       mutex_lock(&tty_mutex);
+       list_del(&driver->tty_drivers);
+       mutex_unlock(&tty_mutex);
+       return 0;
+}
+
+EXPORT_SYMBOL(tty_unregister_driver);
+
+dev_t tty_devnum(struct tty_struct *tty)
+{
+       return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
+}
+EXPORT_SYMBOL(tty_devnum);
+
+void proc_clear_tty(struct task_struct *p)
+{
+       unsigned long flags;
+       struct tty_struct *tty;
+       spin_lock_irqsave(&p->sighand->siglock, flags);
+       tty = p->signal->tty;
+       p->signal->tty = NULL;
+       spin_unlock_irqrestore(&p->sighand->siglock, flags);
+       tty_kref_put(tty);
+}
+
+/* Called under the sighand lock */
+
+static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+{
+       if (tty) {
+               unsigned long flags;
+               /* We should not have a session or pgrp to put here but.... */
+               spin_lock_irqsave(&tty->ctrl_lock, flags);
+               put_pid(tty->session);
+               put_pid(tty->pgrp);
+               tty->pgrp = get_pid(task_pgrp(tsk));
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               tty->session = get_pid(task_session(tsk));
+               if (tsk->signal->tty) {
+                       printk(KERN_DEBUG "tty not NULL!!\n");
+                       tty_kref_put(tsk->signal->tty);
+               }
+       }
+       put_pid(tsk->signal->tty_old_pgrp);
+       tsk->signal->tty = tty_kref_get(tty);
+       tsk->signal->tty_old_pgrp = NULL;
+}
+
+static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+{
+       spin_lock_irq(&tsk->sighand->siglock);
+       __proc_set_tty(tsk, tty);
+       spin_unlock_irq(&tsk->sighand->siglock);
+}
+
+struct tty_struct *get_current_tty(void)
+{
+       struct tty_struct *tty;
+       unsigned long flags;
+
+       spin_lock_irqsave(&current->sighand->siglock, flags);
+       tty = tty_kref_get(current->signal->tty);
+       spin_unlock_irqrestore(&current->sighand->siglock, flags);
+       return tty;
+}
+EXPORT_SYMBOL_GPL(get_current_tty);
+
+void tty_default_fops(struct file_operations *fops)
+{
+       *fops = tty_fops;
+}
+
+/*
+ * Initialize the console device. This is called *early*, so
+ * we can't necessarily depend on lots of kernel help here.
+ * Just do some early initializations, and do the complex setup
+ * later.
+ */
+void __init console_init(void)
+{
+       initcall_t *call;
+
+       /* Setup the default TTY line discipline. */
+       tty_ldisc_begin();
+
+       /*
+        * set up the console device so that later boot sequences can
+        * inform about problems etc..
+        */
+       call = __con_initcall_start;
+       while (call < __con_initcall_end) {
+               (*call)();
+               call++;
+       }
+}
+
+static char *tty_devnode(struct device *dev, mode_t *mode)
+{
+       if (!mode)
+               return NULL;
+       if (dev->devt == MKDEV(TTYAUX_MAJOR, 0) ||
+           dev->devt == MKDEV(TTYAUX_MAJOR, 2))
+               *mode = 0666;
+       return NULL;
+}
+
+static int __init tty_class_init(void)
+{
+       tty_class = class_create(THIS_MODULE, "tty");
+       if (IS_ERR(tty_class))
+               return PTR_ERR(tty_class);
+       tty_class->devnode = tty_devnode;
+       return 0;
+}
+
+postcore_initcall(tty_class_init);
+
+/* 3/2004 jmc: why do these devices exist? */
+
+static struct cdev tty_cdev, console_cdev;
+
+/*
+ * Ok, now we can initialize the rest of the tty devices and can count
+ * on memory allocations, interrupts etc..
+ */
+int __init tty_init(void)
+{
+       cdev_init(&tty_cdev, &tty_fops);
+       if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
+           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
+               panic("Couldn't register /dev/tty driver\n");
+       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
+                             "tty");
+
+       cdev_init(&console_cdev, &console_fops);
+       if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
+           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
+               panic("Couldn't register /dev/console driver\n");
+       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
+                             "console");
+
+#ifdef CONFIG_VT
+       vty_init(&console_fops);
+#endif
+       return 0;
+}
+
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
new file mode 100644 (file)
index 0000000..0c18899
--- /dev/null
@@ -0,0 +1,1179 @@
+/*
+ *  linux/drivers/char/tty_ioctl.c
+ *
+ *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
+ * which can be dynamically activated and de-activated by the line
+ * discipline handling modules (like SLIP).
+ */
+
+#include <linux/types.h>
+#include <linux/termios.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/tty.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/mutex.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#undef TTY_DEBUG_WAIT_UNTIL_SENT
+
+#undef DEBUG
+
+/*
+ * Internal flag options for termios setting behavior
+ */
+#define TERMIOS_FLUSH  1
+#define TERMIOS_WAIT   2
+#define TERMIOS_TERMIO 4
+#define TERMIOS_OLD    8
+
+
+/**
+ *     tty_chars_in_buffer     -       characters pending
+ *     @tty: terminal
+ *
+ *     Return the number of bytes of data in the device private
+ *     output queue. If no private method is supplied there is assumed
+ *     to be no queue on the device.
+ */
+
+int tty_chars_in_buffer(struct tty_struct *tty)
+{
+       if (tty->ops->chars_in_buffer)
+               return tty->ops->chars_in_buffer(tty);
+       else
+               return 0;
+}
+EXPORT_SYMBOL(tty_chars_in_buffer);
+
+/**
+ *     tty_write_room          -       write queue space
+ *     @tty: terminal
+ *
+ *     Return the number of bytes that can be queued to this device
+ *     at the present time. The result should be treated as a guarantee
+ *     and the driver cannot offer a value it later shrinks by more than
+ *     the number of bytes written. If no method is provided 2K is always
+ *     returned and data may be lost as there will be no flow control.
+ */
+int tty_write_room(struct tty_struct *tty)
+{
+       if (tty->ops->write_room)
+               return tty->ops->write_room(tty);
+       return 2048;
+}
+EXPORT_SYMBOL(tty_write_room);
+
+/**
+ *     tty_driver_flush_buffer -       discard internal buffer
+ *     @tty: terminal
+ *
+ *     Discard the internal output buffer for this device. If no method
+ *     is provided then either the buffer cannot be hardware flushed or
+ *     there is no buffer driver side.
+ */
+void tty_driver_flush_buffer(struct tty_struct *tty)
+{
+       if (tty->ops->flush_buffer)
+               tty->ops->flush_buffer(tty);
+}
+EXPORT_SYMBOL(tty_driver_flush_buffer);
+
+/**
+ *     tty_throttle            -       flow control
+ *     @tty: terminal
+ *
+ *     Indicate that a tty should stop transmitting data down the stack.
+ *     Takes the termios mutex to protect against parallel throttle/unthrottle
+ *     and also to ensure the driver can consistently reference its own
+ *     termios data at this point when implementing software flow control.
+ */
+
+void tty_throttle(struct tty_struct *tty)
+{
+       mutex_lock(&tty->termios_mutex);
+       /* check TTY_THROTTLED first so it indicates our state */
+       if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
+           tty->ops->throttle)
+               tty->ops->throttle(tty);
+       mutex_unlock(&tty->termios_mutex);
+}
+EXPORT_SYMBOL(tty_throttle);
+
+/**
+ *     tty_unthrottle          -       flow control
+ *     @tty: terminal
+ *
+ *     Indicate that a tty may continue transmitting data down the stack.
+ *     Takes the termios mutex to protect against parallel throttle/unthrottle
+ *     and also to ensure the driver can consistently reference its own
+ *     termios data at this point when implementing software flow control.
+ *
+ *     Drivers should however remember that the stack can issue a throttle,
+ *     then change flow control method, then unthrottle.
+ */
+
+void tty_unthrottle(struct tty_struct *tty)
+{
+       mutex_lock(&tty->termios_mutex);
+       if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
+           tty->ops->unthrottle)
+               tty->ops->unthrottle(tty);
+       mutex_unlock(&tty->termios_mutex);
+}
+EXPORT_SYMBOL(tty_unthrottle);
+
+/**
+ *     tty_wait_until_sent     -       wait for I/O to finish
+ *     @tty: tty we are waiting for
+ *     @timeout: how long we will wait
+ *
+ *     Wait for characters pending in a tty driver to hit the wire, or
+ *     for a timeout to occur (eg due to flow control)
+ *
+ *     Locking: none
+ */
+
+void tty_wait_until_sent(struct tty_struct *tty, long timeout)
+{
+#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
+       char buf[64];
+
+       printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
+#endif
+       if (!timeout)
+               timeout = MAX_SCHEDULE_TIMEOUT;
+       if (wait_event_interruptible_timeout(tty->write_wait,
+                       !tty_chars_in_buffer(tty), timeout) >= 0) {
+               if (tty->ops->wait_until_sent)
+                       tty->ops->wait_until_sent(tty, timeout);
+       }
+}
+EXPORT_SYMBOL(tty_wait_until_sent);
+
+
+/*
+ *             Termios Helper Methods
+ */
+
+static void unset_locked_termios(struct ktermios *termios,
+                                struct ktermios *old,
+                                struct ktermios *locked)
+{
+       int     i;
+
+#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
+
+       if (!locked) {
+               printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
+               return;
+       }
+
+       NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
+       NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
+       NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
+       NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
+       termios->c_line = locked->c_line ? old->c_line : termios->c_line;
+       for (i = 0; i < NCCS; i++)
+               termios->c_cc[i] = locked->c_cc[i] ?
+                       old->c_cc[i] : termios->c_cc[i];
+       /* FIXME: What should we do for i/ospeed */
+}
+
+/*
+ * Routine which returns the baud rate of the tty
+ *
+ * Note that the baud_table needs to be kept in sync with the
+ * include/asm/termbits.h file.
+ */
+static const speed_t baud_table[] = {
+       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+       9600, 19200, 38400, 57600, 115200, 230400, 460800,
+#ifdef __sparc__
+       76800, 153600, 307200, 614400, 921600
+#else
+       500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
+       2500000, 3000000, 3500000, 4000000
+#endif
+};
+
+#ifndef __sparc__
+static const tcflag_t baud_bits[] = {
+       B0, B50, B75, B110, B134, B150, B200, B300, B600,
+       B1200, B1800, B2400, B4800, B9600, B19200, B38400,
+       B57600, B115200, B230400, B460800, B500000, B576000,
+       B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
+       B3000000, B3500000, B4000000
+};
+#else
+static const tcflag_t baud_bits[] = {
+       B0, B50, B75, B110, B134, B150, B200, B300, B600,
+       B1200, B1800, B2400, B4800, B9600, B19200, B38400,
+       B57600, B115200, B230400, B460800, B76800, B153600,
+       B307200, B614400, B921600
+};
+#endif
+
+static int n_baud_table = ARRAY_SIZE(baud_table);
+
+/**
+ *     tty_termios_baud_rate
+ *     @termios: termios structure
+ *
+ *     Convert termios baud rate data into a speed. This should be called
+ *     with the termios lock held if this termios is a terminal termios
+ *     structure. May change the termios data. Device drivers can call this
+ *     function but should use ->c_[io]speed directly as they are updated.
+ *
+ *     Locking: none
+ */
+
+speed_t tty_termios_baud_rate(struct ktermios *termios)
+{
+       unsigned int cbaud;
+
+       cbaud = termios->c_cflag & CBAUD;
+
+#ifdef BOTHER
+       /* Magic token for arbitary speed via c_ispeed/c_ospeed */
+       if (cbaud == BOTHER)
+               return termios->c_ospeed;
+#endif
+       if (cbaud & CBAUDEX) {
+               cbaud &= ~CBAUDEX;
+
+               if (cbaud < 1 || cbaud + 15 > n_baud_table)
+                       termios->c_cflag &= ~CBAUDEX;
+               else
+                       cbaud += 15;
+       }
+       return baud_table[cbaud];
+}
+EXPORT_SYMBOL(tty_termios_baud_rate);
+
+/**
+ *     tty_termios_input_baud_rate
+ *     @termios: termios structure
+ *
+ *     Convert termios baud rate data into a speed. This should be called
+ *     with the termios lock held if this termios is a terminal termios
+ *     structure. May change the termios data. Device drivers can call this
+ *     function but should use ->c_[io]speed directly as they are updated.
+ *
+ *     Locking: none
+ */
+
+speed_t tty_termios_input_baud_rate(struct ktermios *termios)
+{
+#ifdef IBSHIFT
+       unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
+
+       if (cbaud == B0)
+               return tty_termios_baud_rate(termios);
+
+       /* Magic token for arbitary speed via c_ispeed*/
+       if (cbaud == BOTHER)
+               return termios->c_ispeed;
+
+       if (cbaud & CBAUDEX) {
+               cbaud &= ~CBAUDEX;
+
+               if (cbaud < 1 || cbaud + 15 > n_baud_table)
+                       termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
+               else
+                       cbaud += 15;
+       }
+       return baud_table[cbaud];
+#else
+       return tty_termios_baud_rate(termios);
+#endif
+}
+EXPORT_SYMBOL(tty_termios_input_baud_rate);
+
+/**
+ *     tty_termios_encode_baud_rate
+ *     @termios: ktermios structure holding user requested state
+ *     @ispeed: input speed
+ *     @ospeed: output speed
+ *
+ *     Encode the speeds set into the passed termios structure. This is
+ *     used as a library helper for drivers os that they can report back
+ *     the actual speed selected when it differs from the speed requested
+ *
+ *     For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
+ *     we need to carefully set the bits when the user does not get the
+ *     desired speed. We allow small margins and preserve as much of possible
+ *     of the input intent to keep compatibility.
+ *
+ *     Locking: Caller should hold termios lock. This is already held
+ *     when calling this function from the driver termios handler.
+ *
+ *     The ifdefs deal with platforms whose owners have yet to update them
+ *     and will all go away once this is done.
+ */
+
+void tty_termios_encode_baud_rate(struct ktermios *termios,
+                                 speed_t ibaud, speed_t obaud)
+{
+       int i = 0;
+       int ifound = -1, ofound = -1;
+       int iclose = ibaud/50, oclose = obaud/50;
+       int ibinput = 0;
+
+       if (obaud == 0)                 /* CD dropped             */
+               ibaud = 0;              /* Clear ibaud to be sure */
+
+       termios->c_ispeed = ibaud;
+       termios->c_ospeed = obaud;
+
+#ifdef BOTHER
+       /* If the user asked for a precise weird speed give a precise weird
+          answer. If they asked for a Bfoo speed they many have problems
+          digesting non-exact replies so fuzz a bit */
+
+       if ((termios->c_cflag & CBAUD) == BOTHER)
+               oclose = 0;
+       if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
+               iclose = 0;
+       if ((termios->c_cflag >> IBSHIFT) & CBAUD)
+               ibinput = 1;    /* An input speed was specified */
+#endif
+       termios->c_cflag &= ~CBAUD;
+
+       /*
+        *      Our goal is to find a close match to the standard baud rate
+        *      returned. Walk the baud rate table and if we get a very close
+        *      match then report back the speed as a POSIX Bxxxx value by
+        *      preference
+        */
+
+       do {
+               if (obaud - oclose <= baud_table[i] &&
+                   obaud + oclose >= baud_table[i]) {
+                       termios->c_cflag |= baud_bits[i];
+                       ofound = i;
+               }
+               if (ibaud - iclose <= baud_table[i] &&
+                   ibaud + iclose >= baud_table[i]) {
+                       /* For the case input == output don't set IBAUD bits
+                          if the user didn't do so */
+                       if (ofound == i && !ibinput)
+                               ifound  = i;
+#ifdef IBSHIFT
+                       else {
+                               ifound = i;
+                               termios->c_cflag |= (baud_bits[i] << IBSHIFT);
+                       }
+#endif
+               }
+       } while (++i < n_baud_table);
+
+       /*
+        *      If we found no match then use BOTHER if provided or warn
+        *      the user their platform maintainer needs to wake up if not.
+        */
+#ifdef BOTHER
+       if (ofound == -1)
+               termios->c_cflag |= BOTHER;
+       /* Set exact input bits only if the input and output differ or the
+          user already did */
+       if (ifound == -1 && (ibaud != obaud || ibinput))
+               termios->c_cflag |= (BOTHER << IBSHIFT);
+#else
+       if (ifound == -1 || ofound == -1) {
+               printk_once(KERN_WARNING "tty: Unable to return correct "
+                         "speed data as your architecture needs updating.\n");
+       }
+#endif
+}
+EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
+
+/**
+ *     tty_encode_baud_rate            -       set baud rate of the tty
+ *     @ibaud: input baud rate
+ *     @obad: output baud rate
+ *
+ *     Update the current termios data for the tty with the new speed
+ *     settings. The caller must hold the termios_mutex for the tty in
+ *     question.
+ */
+
+void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
+{
+       tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
+}
+EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
+
+/**
+ *     tty_get_baud_rate       -       get tty bit rates
+ *     @tty: tty to query
+ *
+ *     Returns the baud rate as an integer for this terminal. The
+ *     termios lock must be held by the caller and the terminal bit
+ *     flags may be updated.
+ *
+ *     Locking: none
+ */
+
+speed_t tty_get_baud_rate(struct tty_struct *tty)
+{
+       speed_t baud = tty_termios_baud_rate(tty->termios);
+
+       if (baud == 38400 && tty->alt_speed) {
+               if (!tty->warned) {
+                       printk(KERN_WARNING "Use of setserial/setrocket to "
+                                           "set SPD_* flags is deprecated\n");
+                       tty->warned = 1;
+               }
+               baud = tty->alt_speed;
+       }
+
+       return baud;
+}
+EXPORT_SYMBOL(tty_get_baud_rate);
+
+/**
+ *     tty_termios_copy_hw     -       copy hardware settings
+ *     @new: New termios
+ *     @old: Old termios
+ *
+ *     Propogate the hardware specific terminal setting bits from
+ *     the old termios structure to the new one. This is used in cases
+ *     where the hardware does not support reconfiguration or as a helper
+ *     in some cases where only minimal reconfiguration is supported
+ */
+
+void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
+{
+       /* The bits a dumb device handles in software. Smart devices need
+          to always provide a set_termios method */
+       new->c_cflag &= HUPCL | CREAD | CLOCAL;
+       new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
+       new->c_ispeed = old->c_ispeed;
+       new->c_ospeed = old->c_ospeed;
+}
+EXPORT_SYMBOL(tty_termios_copy_hw);
+
+/**
+ *     tty_termios_hw_change   -       check for setting change
+ *     @a: termios
+ *     @b: termios to compare
+ *
+ *     Check if any of the bits that affect a dumb device have changed
+ *     between the two termios structures, or a speed change is needed.
+ */
+
+int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
+{
+       if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
+               return 1;
+       if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
+               return 1;
+       return 0;
+}
+EXPORT_SYMBOL(tty_termios_hw_change);
+
+/**
+ *     change_termios          -       update termios values
+ *     @tty: tty to update
+ *     @new_termios: desired new value
+ *
+ *     Perform updates to the termios values set on this terminal. There
+ *     is a bit of layering violation here with n_tty in terms of the
+ *     internal knowledge of this function.
+ *
+ *     Locking: termios_mutex
+ */
+
+static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
+{
+       struct ktermios old_termios;
+       struct tty_ldisc *ld;
+       unsigned long flags;
+
+       /*
+        *      Perform the actual termios internal changes under lock.
+        */
+
+
+       /* FIXME: we need to decide on some locking/ordering semantics
+          for the set_termios notification eventually */
+       mutex_lock(&tty->termios_mutex);
+       old_termios = *tty->termios;
+       *tty->termios = *new_termios;
+       unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
+
+       /* See if packet mode change of state. */
+       if (tty->link && tty->link->packet) {
+               int extproc = (old_termios.c_lflag & EXTPROC) |
+                               (tty->termios->c_lflag & EXTPROC);
+               int old_flow = ((old_termios.c_iflag & IXON) &&
+                               (old_termios.c_cc[VSTOP] == '\023') &&
+                               (old_termios.c_cc[VSTART] == '\021'));
+               int new_flow = (I_IXON(tty) &&
+                               STOP_CHAR(tty) == '\023' &&
+                               START_CHAR(tty) == '\021');
+               if ((old_flow != new_flow) || extproc) {
+                       spin_lock_irqsave(&tty->ctrl_lock, flags);
+                       if (old_flow != new_flow) {
+                               tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
+                               if (new_flow)
+                                       tty->ctrl_status |= TIOCPKT_DOSTOP;
+                               else
+                                       tty->ctrl_status |= TIOCPKT_NOSTOP;
+                       }
+                       if (extproc)
+                               tty->ctrl_status |= TIOCPKT_IOCTL;
+                       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+                       wake_up_interruptible(&tty->link->read_wait);
+               }
+       }
+
+       if (tty->ops->set_termios)
+               (*tty->ops->set_termios)(tty, &old_termios);
+       else
+               tty_termios_copy_hw(tty->termios, &old_termios);
+
+       ld = tty_ldisc_ref(tty);
+       if (ld != NULL) {
+               if (ld->ops->set_termios)
+                       (ld->ops->set_termios)(tty, &old_termios);
+               tty_ldisc_deref(ld);
+       }
+       mutex_unlock(&tty->termios_mutex);
+}
+
+/**
+ *     set_termios             -       set termios values for a tty
+ *     @tty: terminal device
+ *     @arg: user data
+ *     @opt: option information
+ *
+ *     Helper function to prepare termios data and run necessary other
+ *     functions before using change_termios to do the actual changes.
+ *
+ *     Locking:
+ *             Called functions take ldisc and termios_mutex locks
+ */
+
+static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
+{
+       struct ktermios tmp_termios;
+       struct tty_ldisc *ld;
+       int retval = tty_check_change(tty);
+
+       if (retval)
+               return retval;
+
+       mutex_lock(&tty->termios_mutex);
+       memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
+       mutex_unlock(&tty->termios_mutex);
+
+       if (opt & TERMIOS_TERMIO) {
+               if (user_termio_to_kernel_termios(&tmp_termios,
+                                               (struct termio __user *)arg))
+                       return -EFAULT;
+#ifdef TCGETS2
+       } else if (opt & TERMIOS_OLD) {
+               if (user_termios_to_kernel_termios_1(&tmp_termios,
+                                               (struct termios __user *)arg))
+                       return -EFAULT;
+       } else {
+               if (user_termios_to_kernel_termios(&tmp_termios,
+                                               (struct termios2 __user *)arg))
+                       return -EFAULT;
+       }
+#else
+       } else if (user_termios_to_kernel_termios(&tmp_termios,
+                                       (struct termios __user *)arg))
+               return -EFAULT;
+#endif
+
+       /* If old style Bfoo values are used then load c_ispeed/c_ospeed
+        * with the real speed so its unconditionally usable */
+       tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
+       tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
+
+       ld = tty_ldisc_ref(tty);
+
+       if (ld != NULL) {
+               if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_ldisc_deref(ld);
+       }
+
+       if (opt & TERMIOS_WAIT) {
+               tty_wait_until_sent(tty, 0);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
+
+       change_termios(tty, &tmp_termios);
+
+       /* FIXME: Arguably if tmp_termios == tty->termios AND the
+          actual requested termios was not tmp_termios then we may
+          want to return an error as no user requested change has
+          succeeded */
+       return 0;
+}
+
+static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
+{
+       mutex_lock(&tty->termios_mutex);
+       memcpy(kterm, tty->termios, sizeof(struct ktermios));
+       mutex_unlock(&tty->termios_mutex);
+}
+
+static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
+{
+       mutex_lock(&tty->termios_mutex);
+       memcpy(kterm, tty->termios_locked, sizeof(struct ktermios));
+       mutex_unlock(&tty->termios_mutex);
+}
+
+static int get_termio(struct tty_struct *tty, struct termio __user *termio)
+{
+       struct ktermios kterm;
+       copy_termios(tty, &kterm);
+       if (kernel_termios_to_user_termio(termio, &kterm))
+               return -EFAULT;
+       return 0;
+}
+
+
+#ifdef TCGETX
+
+/**
+ *     set_termiox     -       set termiox fields if possible
+ *     @tty: terminal
+ *     @arg: termiox structure from user
+ *     @opt: option flags for ioctl type
+ *
+ *     Implement the device calling points for the SYS5 termiox ioctl
+ *     interface in Linux
+ */
+
+static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
+{
+       struct termiox tnew;
+       struct tty_ldisc *ld;
+
+       if (tty->termiox == NULL)
+               return -EINVAL;
+       if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
+               return -EFAULT;
+
+       ld = tty_ldisc_ref(tty);
+       if (ld != NULL) {
+               if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_ldisc_deref(ld);
+       }
+       if (opt & TERMIOS_WAIT) {
+               tty_wait_until_sent(tty, 0);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
+
+       mutex_lock(&tty->termios_mutex);
+       if (tty->ops->set_termiox)
+               tty->ops->set_termiox(tty, &tnew);
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+
+#endif
+
+
+#ifdef TIOCGETP
+/*
+ * These are deprecated, but there is limited support..
+ *
+ * The "sg_flags" translation is a joke..
+ */
+static int get_sgflags(struct tty_struct *tty)
+{
+       int flags = 0;
+
+       if (!(tty->termios->c_lflag & ICANON)) {
+               if (tty->termios->c_lflag & ISIG)
+                       flags |= 0x02;          /* cbreak */
+               else
+                       flags |= 0x20;          /* raw */
+       }
+       if (tty->termios->c_lflag & ECHO)
+               flags |= 0x08;                  /* echo */
+       if (tty->termios->c_oflag & OPOST)
+               if (tty->termios->c_oflag & ONLCR)
+                       flags |= 0x10;          /* crmod */
+       return flags;
+}
+
+static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
+{
+       struct sgttyb tmp;
+
+       mutex_lock(&tty->termios_mutex);
+       tmp.sg_ispeed = tty->termios->c_ispeed;
+       tmp.sg_ospeed = tty->termios->c_ospeed;
+       tmp.sg_erase = tty->termios->c_cc[VERASE];
+       tmp.sg_kill = tty->termios->c_cc[VKILL];
+       tmp.sg_flags = get_sgflags(tty);
+       mutex_unlock(&tty->termios_mutex);
+
+       return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
+}
+
+static void set_sgflags(struct ktermios *termios, int flags)
+{
+       termios->c_iflag = ICRNL | IXON;
+       termios->c_oflag = 0;
+       termios->c_lflag = ISIG | ICANON;
+       if (flags & 0x02) {     /* cbreak */
+               termios->c_iflag = 0;
+               termios->c_lflag &= ~ICANON;
+       }
+       if (flags & 0x08) {             /* echo */
+               termios->c_lflag |= ECHO | ECHOE | ECHOK |
+                                   ECHOCTL | ECHOKE | IEXTEN;
+       }
+       if (flags & 0x10) {             /* crmod */
+               termios->c_oflag |= OPOST | ONLCR;
+       }
+       if (flags & 0x20) {     /* raw */
+               termios->c_iflag = 0;
+               termios->c_lflag &= ~(ISIG | ICANON);
+       }
+       if (!(termios->c_lflag & ICANON)) {
+               termios->c_cc[VMIN] = 1;
+               termios->c_cc[VTIME] = 0;
+       }
+}
+
+/**
+ *     set_sgttyb              -       set legacy terminal values
+ *     @tty: tty structure
+ *     @sgttyb: pointer to old style terminal structure
+ *
+ *     Updates a terminal from the legacy BSD style terminal information
+ *     structure.
+ *
+ *     Locking: termios_mutex
+ */
+
+static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
+{
+       int retval;
+       struct sgttyb tmp;
+       struct ktermios termios;
+
+       retval = tty_check_change(tty);
+       if (retval)
+               return retval;
+
+       if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
+               return -EFAULT;
+
+       mutex_lock(&tty->termios_mutex);
+       termios = *tty->termios;
+       termios.c_cc[VERASE] = tmp.sg_erase;
+       termios.c_cc[VKILL] = tmp.sg_kill;
+       set_sgflags(&termios, tmp.sg_flags);
+       /* Try and encode into Bfoo format */
+#ifdef BOTHER
+       tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
+                                               termios.c_ospeed);
+#endif
+       mutex_unlock(&tty->termios_mutex);
+       change_termios(tty, &termios);
+       return 0;
+}
+#endif
+
+#ifdef TIOCGETC
+static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
+{
+       struct tchars tmp;
+
+       mutex_lock(&tty->termios_mutex);
+       tmp.t_intrc = tty->termios->c_cc[VINTR];
+       tmp.t_quitc = tty->termios->c_cc[VQUIT];
+       tmp.t_startc = tty->termios->c_cc[VSTART];
+       tmp.t_stopc = tty->termios->c_cc[VSTOP];
+       tmp.t_eofc = tty->termios->c_cc[VEOF];
+       tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
+       mutex_unlock(&tty->termios_mutex);
+       return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
+}
+
+static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
+{
+       struct tchars tmp;
+
+       if (copy_from_user(&tmp, tchars, sizeof(tmp)))
+               return -EFAULT;
+       mutex_lock(&tty->termios_mutex);
+       tty->termios->c_cc[VINTR] = tmp.t_intrc;
+       tty->termios->c_cc[VQUIT] = tmp.t_quitc;
+       tty->termios->c_cc[VSTART] = tmp.t_startc;
+       tty->termios->c_cc[VSTOP] = tmp.t_stopc;
+       tty->termios->c_cc[VEOF] = tmp.t_eofc;
+       tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+#endif
+
+#ifdef TIOCGLTC
+static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
+{
+       struct ltchars tmp;
+
+       mutex_lock(&tty->termios_mutex);
+       tmp.t_suspc = tty->termios->c_cc[VSUSP];
+       /* what is dsuspc anyway? */
+       tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
+       tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
+       /* what is flushc anyway? */
+       tmp.t_flushc = tty->termios->c_cc[VEOL2];
+       tmp.t_werasc = tty->termios->c_cc[VWERASE];
+       tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
+       mutex_unlock(&tty->termios_mutex);
+       return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
+}
+
+static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
+{
+       struct ltchars tmp;
+
+       if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
+               return -EFAULT;
+
+       mutex_lock(&tty->termios_mutex);
+       tty->termios->c_cc[VSUSP] = tmp.t_suspc;
+       /* what is dsuspc anyway? */
+       tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
+       tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
+       /* what is flushc anyway? */
+       tty->termios->c_cc[VEOL2] = tmp.t_flushc;
+       tty->termios->c_cc[VWERASE] = tmp.t_werasc;
+       tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+#endif
+
+/**
+ *     send_prio_char          -       send priority character
+ *
+ *     Send a high priority character to the tty even if stopped
+ *
+ *     Locking: none for xchar method, write ordering for write method.
+ */
+
+static int send_prio_char(struct tty_struct *tty, char ch)
+{
+       int     was_stopped = tty->stopped;
+
+       if (tty->ops->send_xchar) {
+               tty->ops->send_xchar(tty, ch);
+               return 0;
+       }
+
+       if (tty_write_lock(tty, 0) < 0)
+               return -ERESTARTSYS;
+
+       if (was_stopped)
+               start_tty(tty);
+       tty->ops->write(tty, &ch, 1);
+       if (was_stopped)
+               stop_tty(tty);
+       tty_write_unlock(tty);
+       return 0;
+}
+
+/**
+ *     tty_change_softcar      -       carrier change ioctl helper
+ *     @tty: tty to update
+ *     @arg: enable/disable CLOCAL
+ *
+ *     Perform a change to the CLOCAL state and call into the driver
+ *     layer to make it visible. All done with the termios mutex
+ */
+
+static int tty_change_softcar(struct tty_struct *tty, int arg)
+{
+       int ret = 0;
+       int bit = arg ? CLOCAL : 0;
+       struct ktermios old;
+
+       mutex_lock(&tty->termios_mutex);
+       old = *tty->termios;
+       tty->termios->c_cflag &= ~CLOCAL;
+       tty->termios->c_cflag |= bit;
+       if (tty->ops->set_termios)
+               tty->ops->set_termios(tty, &old);
+       if ((tty->termios->c_cflag & CLOCAL) != bit)
+               ret = -EINVAL;
+       mutex_unlock(&tty->termios_mutex);
+       return ret;
+}
+
+/**
+ *     tty_mode_ioctl          -       mode related ioctls
+ *     @tty: tty for the ioctl
+ *     @file: file pointer for the tty
+ *     @cmd: command
+ *     @arg: ioctl argument
+ *
+ *     Perform non line discipline specific mode control ioctls. This
+ *     is designed to be called by line disciplines to ensure they provide
+ *     consistent mode setting.
+ */
+
+int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+{
+       struct tty_struct *real_tty;
+       void __user *p = (void __user *)arg;
+       int ret = 0;
+       struct ktermios kterm;
+
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_MASTER)
+               real_tty = tty->link;
+       else
+               real_tty = tty;
+
+       switch (cmd) {
+#ifdef TIOCGETP
+       case TIOCGETP:
+               return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
+       case TIOCSETP:
+       case TIOCSETN:
+               return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
+#endif
+#ifdef TIOCGETC
+       case TIOCGETC:
+               return get_tchars(real_tty, p);
+       case TIOCSETC:
+               return set_tchars(real_tty, p);
+#endif
+#ifdef TIOCGLTC
+       case TIOCGLTC:
+               return get_ltchars(real_tty, p);
+       case TIOCSLTC:
+               return set_ltchars(real_tty, p);
+#endif
+       case TCSETSF:
+               return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
+       case TCSETSW:
+               return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
+       case TCSETS:
+               return set_termios(real_tty, p, TERMIOS_OLD);
+#ifndef TCGETS2
+       case TCGETS:
+               copy_termios(real_tty, &kterm);
+               if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
+                       ret = -EFAULT;
+               return ret;
+#else
+       case TCGETS:
+               copy_termios(real_tty, &kterm);
+               if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
+                       ret = -EFAULT;
+               return ret;
+       case TCGETS2:
+               copy_termios(real_tty, &kterm);
+               if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
+                       ret = -EFAULT;
+               return ret;
+       case TCSETSF2:
+               return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
+       case TCSETSW2:
+               return set_termios(real_tty, p, TERMIOS_WAIT);
+       case TCSETS2:
+               return set_termios(real_tty, p, 0);
+#endif
+       case TCGETA:
+               return get_termio(real_tty, p);
+       case TCSETAF:
+               return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
+       case TCSETAW:
+               return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
+       case TCSETA:
+               return set_termios(real_tty, p, TERMIOS_TERMIO);
+#ifndef TCGETS2
+       case TIOCGLCKTRMIOS:
+               copy_termios_locked(real_tty, &kterm);
+               if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
+                       ret = -EFAULT;
+               return ret;
+       case TIOCSLCKTRMIOS:
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               copy_termios_locked(real_tty, &kterm);
+               if (user_termios_to_kernel_termios(&kterm,
+                                              (struct termios __user *) arg))
+                       return -EFAULT;
+               mutex_lock(&real_tty->termios_mutex);
+               memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
+               mutex_unlock(&real_tty->termios_mutex);
+               return 0;
+#else
+       case TIOCGLCKTRMIOS:
+               copy_termios_locked(real_tty, &kterm);
+               if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
+                       ret = -EFAULT;
+               return ret;
+       case TIOCSLCKTRMIOS:
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               copy_termios_locked(real_tty, &kterm);
+               if (user_termios_to_kernel_termios_1(&kterm,
+                                              (struct termios __user *) arg))
+                       return -EFAULT;
+               mutex_lock(&real_tty->termios_mutex);
+               memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
+#endif
+#ifdef TCGETX
+       case TCGETX: {
+               struct termiox ktermx;
+               if (real_tty->termiox == NULL)
+                       return -EINVAL;
+               mutex_lock(&real_tty->termios_mutex);
+               memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
+               mutex_unlock(&real_tty->termios_mutex);
+               if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
+                       ret = -EFAULT;
+               return ret;
+       }
+       case TCSETX:
+               return set_termiox(real_tty, p, 0);
+       case TCSETXW:
+               return set_termiox(real_tty, p, TERMIOS_WAIT);
+       case TCSETXF:
+               return set_termiox(real_tty, p, TERMIOS_FLUSH);
+#endif         
+       case TIOCGSOFTCAR:
+               copy_termios(real_tty, &kterm);
+               ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
+                                               (int __user *)arg);
+               return ret;
+       case TIOCSSOFTCAR:
+               if (get_user(arg, (unsigned int __user *) arg))
+                       return -EFAULT;
+               return tty_change_softcar(real_tty, arg);
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+EXPORT_SYMBOL_GPL(tty_mode_ioctl);
+
+int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
+{
+       struct tty_ldisc *ld;
+       int retval = tty_check_change(tty);
+       if (retval)
+               return retval;
+
+       ld = tty_ldisc_ref_wait(tty);
+       switch (arg) {
+       case TCIFLUSH:
+               if (ld && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               break;
+       case TCIOFLUSH:
+               if (ld && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               /* fall through */
+       case TCOFLUSH:
+               tty_driver_flush_buffer(tty);
+               break;
+       default:
+               tty_ldisc_deref(ld);
+               return -EINVAL;
+       }
+       tty_ldisc_deref(ld);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tty_perform_flush);
+
+int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       unsigned long flags;
+       int retval;
+
+       switch (cmd) {
+       case TCXONC:
+               retval = tty_check_change(tty);
+               if (retval)
+                       return retval;
+               switch (arg) {
+               case TCOOFF:
+                       if (!tty->flow_stopped) {
+                               tty->flow_stopped = 1;
+                               stop_tty(tty);
+                       }
+                       break;
+               case TCOON:
+                       if (tty->flow_stopped) {
+                               tty->flow_stopped = 0;
+                               start_tty(tty);
+                       }
+                       break;
+               case TCIOFF:
+                       if (STOP_CHAR(tty) != __DISABLED_CHAR)
+                               return send_prio_char(tty, STOP_CHAR(tty));
+                       break;
+               case TCION:
+                       if (START_CHAR(tty) != __DISABLED_CHAR)
+                               return send_prio_char(tty, START_CHAR(tty));
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               return 0;
+       case TCFLSH:
+               return tty_perform_flush(tty, arg);
+       case TIOCPKT:
+       {
+               int pktmode;
+
+               if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
+                   tty->driver->subtype != PTY_TYPE_MASTER)
+                       return -ENOTTY;
+               if (get_user(pktmode, (int __user *) arg))
+                       return -EFAULT;
+               spin_lock_irqsave(&tty->ctrl_lock, flags);
+               if (pktmode) {
+                       if (!tty->packet) {
+                               tty->packet = 1;
+                               tty->link->ctrl_status = 0;
+                       }
+               } else
+                       tty->packet = 0;
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               return 0;
+       }
+       default:
+               /* Try the mode commands */
+               return tty_mode_ioctl(tty, file, cmd, arg);
+       }
+}
+EXPORT_SYMBOL(n_tty_ioctl_helper);
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
new file mode 100644 (file)
index 0000000..412f977
--- /dev/null
@@ -0,0 +1,915 @@
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/devpts_fs.h>
+#include <linux/file.h>
+#include <linux/console.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/kd.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+
+#include <linux/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+
+#include <linux/smp_lock.h>    /* For the moment */
+
+#include <linux/kmod.h>
+#include <linux/nsproxy.h>
+
+/*
+ *     This guards the refcounted line discipline lists. The lock
+ *     must be taken with irqs off because there are hangup path
+ *     callers who will do ldisc lookups and cannot sleep.
+ */
+
+static DEFINE_SPINLOCK(tty_ldisc_lock);
+static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
+/* Line disc dispatch table */
+static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
+
+static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld)
+{
+       if (ld)
+               atomic_inc(&ld->users);
+       return ld;
+}
+
+static void put_ldisc(struct tty_ldisc *ld)
+{
+       unsigned long flags;
+
+       if (WARN_ON_ONCE(!ld))
+               return;
+
+       /*
+        * If this is the last user, free the ldisc, and
+        * release the ldisc ops.
+        *
+        * We really want an "atomic_dec_and_lock_irqsave()",
+        * but we don't have it, so this does it by hand.
+        */
+       local_irq_save(flags);
+       if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) {
+               struct tty_ldisc_ops *ldo = ld->ops;
+
+               ldo->refcount--;
+               module_put(ldo->owner);
+               spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+               kfree(ld);
+               return;
+       }
+       local_irq_restore(flags);
+}
+
+/**
+ *     tty_register_ldisc      -       install a line discipline
+ *     @disc: ldisc number
+ *     @new_ldisc: pointer to the ldisc object
+ *
+ *     Installs a new line discipline into the kernel. The discipline
+ *     is set up as unreferenced and then made available to the kernel
+ *     from this point onwards.
+ *
+ *     Locking:
+ *             takes tty_ldisc_lock to guard against ldisc races
+ */
+
+int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       if (disc < N_TTY || disc >= NR_LDISCS)
+               return -EINVAL;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       tty_ldiscs[disc] = new_ldisc;
+       new_ldisc->num = disc;
+       new_ldisc->refcount = 0;
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(tty_register_ldisc);
+
+/**
+ *     tty_unregister_ldisc    -       unload a line discipline
+ *     @disc: ldisc number
+ *     @new_ldisc: pointer to the ldisc object
+ *
+ *     Remove a line discipline from the kernel providing it is not
+ *     currently in use.
+ *
+ *     Locking:
+ *             takes tty_ldisc_lock to guard against ldisc races
+ */
+
+int tty_unregister_ldisc(int disc)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       if (disc < N_TTY || disc >= NR_LDISCS)
+               return -EINVAL;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       if (tty_ldiscs[disc]->refcount)
+               ret = -EBUSY;
+       else
+               tty_ldiscs[disc] = NULL;
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(tty_unregister_ldisc);
+
+static struct tty_ldisc_ops *get_ldops(int disc)
+{
+       unsigned long flags;
+       struct tty_ldisc_ops *ldops, *ret;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       ret = ERR_PTR(-EINVAL);
+       ldops = tty_ldiscs[disc];
+       if (ldops) {
+               ret = ERR_PTR(-EAGAIN);
+               if (try_module_get(ldops->owner)) {
+                       ldops->refcount++;
+                       ret = ldops;
+               }
+       }
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+       return ret;
+}
+
+static void put_ldops(struct tty_ldisc_ops *ldops)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       ldops->refcount--;
+       module_put(ldops->owner);
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+}
+
+/**
+ *     tty_ldisc_get           -       take a reference to an ldisc
+ *     @disc: ldisc number
+ *
+ *     Takes a reference to a line discipline. Deals with refcounts and
+ *     module locking counts. Returns NULL if the discipline is not available.
+ *     Returns a pointer to the discipline and bumps the ref count if it is
+ *     available
+ *
+ *     Locking:
+ *             takes tty_ldisc_lock to guard against ldisc races
+ */
+
+static struct tty_ldisc *tty_ldisc_get(int disc)
+{
+       struct tty_ldisc *ld;
+       struct tty_ldisc_ops *ldops;
+
+       if (disc < N_TTY || disc >= NR_LDISCS)
+               return ERR_PTR(-EINVAL);
+
+       /*
+        * Get the ldisc ops - we may need to request them to be loaded
+        * dynamically and try again.
+        */
+       ldops = get_ldops(disc);
+       if (IS_ERR(ldops)) {
+               request_module("tty-ldisc-%d", disc);
+               ldops = get_ldops(disc);
+               if (IS_ERR(ldops))
+                       return ERR_CAST(ldops);
+       }
+
+       ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
+       if (ld == NULL) {
+               put_ldops(ldops);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       ld->ops = ldops;
+       atomic_set(&ld->users, 1);
+       return ld;
+}
+
+static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
+{
+       return (*pos < NR_LDISCS) ? pos : NULL;
+}
+
+static void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       (*pos)++;
+       return (*pos < NR_LDISCS) ? pos : NULL;
+}
+
+static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
+{
+}
+
+static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
+{
+       int i = *(loff_t *)v;
+       struct tty_ldisc_ops *ldops;
+
+       ldops = get_ldops(i);
+       if (IS_ERR(ldops))
+               return 0;
+       seq_printf(m, "%-10s %2d\n", ldops->name ? ldops->name : "???", i);
+       put_ldops(ldops);
+       return 0;
+}
+
+static const struct seq_operations tty_ldiscs_seq_ops = {
+       .start  = tty_ldiscs_seq_start,
+       .next   = tty_ldiscs_seq_next,
+       .stop   = tty_ldiscs_seq_stop,
+       .show   = tty_ldiscs_seq_show,
+};
+
+static int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &tty_ldiscs_seq_ops);
+}
+
+const struct file_operations tty_ldiscs_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = proc_tty_ldiscs_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+/**
+ *     tty_ldisc_assign        -       set ldisc on a tty
+ *     @tty: tty to assign
+ *     @ld: line discipline
+ *
+ *     Install an instance of a line discipline into a tty structure. The
+ *     ldisc must have a reference count above zero to ensure it remains.
+ *     The tty instance refcount starts at zero.
+ *
+ *     Locking:
+ *             Caller must hold references
+ */
+
+static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
+{
+       tty->ldisc = ld;
+}
+
+/**
+ *     tty_ldisc_try           -       internal helper
+ *     @tty: the tty
+ *
+ *     Make a single attempt to grab and bump the refcount on
+ *     the tty ldisc. Return 0 on failure or 1 on success. This is
+ *     used to implement both the waiting and non waiting versions
+ *     of tty_ldisc_ref
+ *
+ *     Locking: takes tty_ldisc_lock
+ */
+
+static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
+{
+       unsigned long flags;
+       struct tty_ldisc *ld;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       ld = NULL;
+       if (test_bit(TTY_LDISC, &tty->flags))
+               ld = get_ldisc(tty->ldisc);
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+       return ld;
+}
+
+/**
+ *     tty_ldisc_ref_wait      -       wait for the tty ldisc
+ *     @tty: tty device
+ *
+ *     Dereference the line discipline for the terminal and take a
+ *     reference to it. If the line discipline is in flux then
+ *     wait patiently until it changes.
+ *
+ *     Note: Must not be called from an IRQ/timer context. The caller
+ *     must also be careful not to hold other locks that will deadlock
+ *     against a discipline change, such as an existing ldisc reference
+ *     (which we check for)
+ *
+ *     Locking: call functions take tty_ldisc_lock
+ */
+
+struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld;
+
+       /* wait_event is a macro */
+       wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL);
+       return ld;
+}
+EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
+
+/**
+ *     tty_ldisc_ref           -       get the tty ldisc
+ *     @tty: tty device
+ *
+ *     Dereference the line discipline for the terminal and take a
+ *     reference to it. If the line discipline is in flux then
+ *     return NULL. Can be called from IRQ and timer functions.
+ *
+ *     Locking: called functions take tty_ldisc_lock
+ */
+
+struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
+{
+       return tty_ldisc_try(tty);
+}
+EXPORT_SYMBOL_GPL(tty_ldisc_ref);
+
+/**
+ *     tty_ldisc_deref         -       free a tty ldisc reference
+ *     @ld: reference to free up
+ *
+ *     Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May
+ *     be called in IRQ context.
+ *
+ *     Locking: takes tty_ldisc_lock
+ */
+
+void tty_ldisc_deref(struct tty_ldisc *ld)
+{
+       put_ldisc(ld);
+}
+EXPORT_SYMBOL_GPL(tty_ldisc_deref);
+
+static inline void tty_ldisc_put(struct tty_ldisc *ld)
+{
+       put_ldisc(ld);
+}
+
+/**
+ *     tty_ldisc_enable        -       allow ldisc use
+ *     @tty: terminal to activate ldisc on
+ *
+ *     Set the TTY_LDISC flag when the line discipline can be called
+ *     again. Do necessary wakeups for existing sleepers. Clear the LDISC
+ *     changing flag to indicate any ldisc change is now over.
+ *
+ *     Note: nobody should set the TTY_LDISC bit except via this function.
+ *     Clearing directly is allowed.
+ */
+
+void tty_ldisc_enable(struct tty_struct *tty)
+{
+       set_bit(TTY_LDISC, &tty->flags);
+       clear_bit(TTY_LDISC_CHANGING, &tty->flags);
+       wake_up(&tty_ldisc_wait);
+}
+
+/**
+ *     tty_ldisc_flush -       flush line discipline queue
+ *     @tty: tty
+ *
+ *     Flush the line discipline queue (if any) for this tty. If there
+ *     is no line discipline active this is a no-op.
+ */
+
+void tty_ldisc_flush(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld = tty_ldisc_ref(tty);
+       if (ld) {
+               if (ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_ldisc_deref(ld);
+       }
+       tty_buffer_flush(tty);
+}
+EXPORT_SYMBOL_GPL(tty_ldisc_flush);
+
+/**
+ *     tty_set_termios_ldisc           -       set ldisc field
+ *     @tty: tty structure
+ *     @num: line discipline number
+ *
+ *     This is probably overkill for real world processors but
+ *     they are not on hot paths so a little discipline won't do
+ *     any harm.
+ *
+ *     Locking: takes termios_mutex
+ */
+
+static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
+{
+       mutex_lock(&tty->termios_mutex);
+       tty->termios->c_line = num;
+       mutex_unlock(&tty->termios_mutex);
+}
+
+/**
+ *     tty_ldisc_open          -       open a line discipline
+ *     @tty: tty we are opening the ldisc on
+ *     @ld: discipline to open
+ *
+ *     A helper opening method. Also a convenient debugging and check
+ *     point.
+ *
+ *     Locking: always called with BTM already held.
+ */
+
+static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
+{
+       WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
+       if (ld->ops->open) {
+               int ret;
+                /* BTM here locks versus a hangup event */
+               WARN_ON(!tty_locked());
+               ret = ld->ops->open(tty);
+               return ret;
+       }
+       return 0;
+}
+
+/**
+ *     tty_ldisc_close         -       close a line discipline
+ *     @tty: tty we are opening the ldisc on
+ *     @ld: discipline to close
+ *
+ *     A helper close method. Also a convenient debugging and check
+ *     point.
+ */
+
+static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
+{
+       WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
+       clear_bit(TTY_LDISC_OPEN, &tty->flags);
+       if (ld->ops->close)
+               ld->ops->close(tty);
+}
+
+/**
+ *     tty_ldisc_restore       -       helper for tty ldisc change
+ *     @tty: tty to recover
+ *     @old: previous ldisc
+ *
+ *     Restore the previous line discipline or N_TTY when a line discipline
+ *     change fails due to an open error
+ */
+
+static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
+{
+       char buf[64];
+       struct tty_ldisc *new_ldisc;
+       int r;
+
+       /* There is an outstanding reference here so this is safe */
+       old = tty_ldisc_get(old->ops->num);
+       WARN_ON(IS_ERR(old));
+       tty_ldisc_assign(tty, old);
+       tty_set_termios_ldisc(tty, old->ops->num);
+       if (tty_ldisc_open(tty, old) < 0) {
+               tty_ldisc_put(old);
+               /* This driver is always present */
+               new_ldisc = tty_ldisc_get(N_TTY);
+               if (IS_ERR(new_ldisc))
+                       panic("n_tty: get");
+               tty_ldisc_assign(tty, new_ldisc);
+               tty_set_termios_ldisc(tty, N_TTY);
+               r = tty_ldisc_open(tty, new_ldisc);
+               if (r < 0)
+                       panic("Couldn't open N_TTY ldisc for "
+                             "%s --- error %d.",
+                             tty_name(tty, buf), r);
+       }
+}
+
+/**
+ *     tty_ldisc_halt          -       shut down the line discipline
+ *     @tty: tty device
+ *
+ *     Shut down the line discipline and work queue for this tty device.
+ *     The TTY_LDISC flag being cleared ensures no further references can
+ *     be obtained while the delayed work queue halt ensures that no more
+ *     data is fed to the ldisc.
+ *
+ *     You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex)
+ *     in order to make sure any currently executing ldisc work is also
+ *     flushed.
+ */
+
+static int tty_ldisc_halt(struct tty_struct *tty)
+{
+       clear_bit(TTY_LDISC, &tty->flags);
+       return cancel_delayed_work_sync(&tty->buf.work);
+}
+
+/**
+ *     tty_set_ldisc           -       set line discipline
+ *     @tty: the terminal to set
+ *     @ldisc: the line discipline
+ *
+ *     Set the discipline of a tty line. Must be called from a process
+ *     context. The ldisc change logic has to protect itself against any
+ *     overlapping ldisc change (including on the other end of pty pairs),
+ *     the close of one side of a tty/pty pair, and eventually hangup.
+ *
+ *     Locking: takes tty_ldisc_lock, termios_mutex
+ */
+
+int tty_set_ldisc(struct tty_struct *tty, int ldisc)
+{
+       int retval;
+       struct tty_ldisc *o_ldisc, *new_ldisc;
+       int work, o_work = 0;
+       struct tty_struct *o_tty;
+
+       new_ldisc = tty_ldisc_get(ldisc);
+       if (IS_ERR(new_ldisc))
+               return PTR_ERR(new_ldisc);
+
+       tty_lock();
+       /*
+        *      We need to look at the tty locking here for pty/tty pairs
+        *      when both sides try to change in parallel.
+        */
+
+       o_tty = tty->link;      /* o_tty is the pty side or NULL */
+
+
+       /*
+        *      Check the no-op case
+        */
+
+       if (tty->ldisc->ops->num == ldisc) {
+               tty_unlock();
+               tty_ldisc_put(new_ldisc);
+               return 0;
+       }
+
+       tty_unlock();
+       /*
+        *      Problem: What do we do if this blocks ?
+        *      We could deadlock here
+        */
+
+       tty_wait_until_sent(tty, 0);
+
+       tty_lock();
+       mutex_lock(&tty->ldisc_mutex);
+
+       /*
+        *      We could be midstream of another ldisc change which has
+        *      dropped the lock during processing. If so we need to wait.
+        */
+
+       while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
+               mutex_unlock(&tty->ldisc_mutex);
+               tty_unlock();
+               wait_event(tty_ldisc_wait,
+                       test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
+               tty_lock();
+               mutex_lock(&tty->ldisc_mutex);
+       }
+
+       set_bit(TTY_LDISC_CHANGING, &tty->flags);
+
+       /*
+        *      No more input please, we are switching. The new ldisc
+        *      will update this value in the ldisc open function
+        */
+
+       tty->receive_room = 0;
+
+       o_ldisc = tty->ldisc;
+
+       tty_unlock();
+       /*
+        *      Make sure we don't change while someone holds a
+        *      reference to the line discipline. The TTY_LDISC bit
+        *      prevents anyone taking a reference once it is clear.
+        *      We need the lock to avoid racing reference takers.
+        *
+        *      We must clear the TTY_LDISC bit here to avoid a livelock
+        *      with a userspace app continually trying to use the tty in
+        *      parallel to the change and re-referencing the tty.
+        */
+
+       work = tty_ldisc_halt(tty);
+       if (o_tty)
+               o_work = tty_ldisc_halt(o_tty);
+
+       /*
+        * Wait for ->hangup_work and ->buf.work handlers to terminate.
+        * We must drop the mutex here in case a hangup is also in process.
+        */
+
+       mutex_unlock(&tty->ldisc_mutex);
+
+       flush_scheduled_work();
+
+       tty_lock();
+       mutex_lock(&tty->ldisc_mutex);
+       if (test_bit(TTY_HUPPED, &tty->flags)) {
+               /* We were raced by the hangup method. It will have stomped
+                  the ldisc data and closed the ldisc down */
+               clear_bit(TTY_LDISC_CHANGING, &tty->flags);
+               mutex_unlock(&tty->ldisc_mutex);
+               tty_ldisc_put(new_ldisc);
+               tty_unlock();
+               return -EIO;
+       }
+
+       /* Shutdown the current discipline. */
+       tty_ldisc_close(tty, o_ldisc);
+
+       /* Now set up the new line discipline. */
+       tty_ldisc_assign(tty, new_ldisc);
+       tty_set_termios_ldisc(tty, ldisc);
+
+       retval = tty_ldisc_open(tty, new_ldisc);
+       if (retval < 0) {
+               /* Back to the old one or N_TTY if we can't */
+               tty_ldisc_put(new_ldisc);
+               tty_ldisc_restore(tty, o_ldisc);
+       }
+
+       /* At this point we hold a reference to the new ldisc and a
+          a reference to the old ldisc. If we ended up flipping back
+          to the existing ldisc we have two references to it */
+
+       if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc)
+               tty->ops->set_ldisc(tty);
+
+       tty_ldisc_put(o_ldisc);
+
+       /*
+        *      Allow ldisc referencing to occur again
+        */
+
+       tty_ldisc_enable(tty);
+       if (o_tty)
+               tty_ldisc_enable(o_tty);
+
+       /* Restart the work queue in case no characters kick it off. Safe if
+          already running */
+       if (work)
+               schedule_delayed_work(&tty->buf.work, 1);
+       if (o_work)
+               schedule_delayed_work(&o_tty->buf.work, 1);
+       mutex_unlock(&tty->ldisc_mutex);
+       tty_unlock();
+       return retval;
+}
+
+/**
+ *     tty_reset_termios       -       reset terminal state
+ *     @tty: tty to reset
+ *
+ *     Restore a terminal to the driver default state.
+ */
+
+static void tty_reset_termios(struct tty_struct *tty)
+{
+       mutex_lock(&tty->termios_mutex);
+       *tty->termios = tty->driver->init_termios;
+       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
+       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+       mutex_unlock(&tty->termios_mutex);
+}
+
+
+/**
+ *     tty_ldisc_reinit        -       reinitialise the tty ldisc
+ *     @tty: tty to reinit
+ *     @ldisc: line discipline to reinitialize
+ *
+ *     Switch the tty to a line discipline and leave the ldisc
+ *     state closed
+ */
+
+static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
+{
+       struct tty_ldisc *ld;
+
+       tty_ldisc_close(tty, tty->ldisc);
+       tty_ldisc_put(tty->ldisc);
+       tty->ldisc = NULL;
+       /*
+        *      Switch the line discipline back
+        */
+       ld = tty_ldisc_get(ldisc);
+       BUG_ON(IS_ERR(ld));
+       tty_ldisc_assign(tty, ld);
+       tty_set_termios_ldisc(tty, ldisc);
+}
+
+/**
+ *     tty_ldisc_hangup                -       hangup ldisc reset
+ *     @tty: tty being hung up
+ *
+ *     Some tty devices reset their termios when they receive a hangup
+ *     event. In that situation we must also switch back to N_TTY properly
+ *     before we reset the termios data.
+ *
+ *     Locking: We can take the ldisc mutex as the rest of the code is
+ *     careful to allow for this.
+ *
+ *     In the pty pair case this occurs in the close() path of the
+ *     tty itself so we must be careful about locking rules.
+ */
+
+void tty_ldisc_hangup(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld;
+       int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
+       int err = 0;
+
+       /*
+        * FIXME! What are the locking issues here? This may me overdoing
+        * things... This question is especially important now that we've
+        * removed the irqlock.
+        */
+       ld = tty_ldisc_ref(tty);
+       if (ld != NULL) {
+               /* We may have no line discipline at this point */
+               if (ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_driver_flush_buffer(tty);
+               if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
+                   ld->ops->write_wakeup)
+                       ld->ops->write_wakeup(tty);
+               if (ld->ops->hangup)
+                       ld->ops->hangup(tty);
+               tty_ldisc_deref(ld);
+       }
+       /*
+        * FIXME: Once we trust the LDISC code better we can wait here for
+        * ldisc completion and fix the driver call race
+        */
+       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
+       wake_up_interruptible_poll(&tty->read_wait, POLLIN);
+       /*
+        * Shutdown the current line discipline, and reset it to
+        * N_TTY if need be.
+        *
+        * Avoid racing set_ldisc or tty_ldisc_release
+        */
+       mutex_lock(&tty->ldisc_mutex);
+
+       /*
+        * this is like tty_ldisc_halt, but we need to give up
+        * the BTM before calling cancel_delayed_work_sync,
+        * which may need to wait for another function taking the BTM
+        */
+       clear_bit(TTY_LDISC, &tty->flags);
+       tty_unlock();
+       cancel_delayed_work_sync(&tty->buf.work);
+       mutex_unlock(&tty->ldisc_mutex);
+
+       tty_lock();
+       mutex_lock(&tty->ldisc_mutex);
+
+       /* At this point we have a closed ldisc and we want to
+          reopen it. We could defer this to the next open but
+          it means auditing a lot of other paths so this is
+          a FIXME */
+       if (tty->ldisc) {       /* Not yet closed */
+               if (reset == 0) {
+                       tty_ldisc_reinit(tty, tty->termios->c_line);
+                       err = tty_ldisc_open(tty, tty->ldisc);
+               }
+               /* If the re-open fails or we reset then go to N_TTY. The
+                  N_TTY open cannot fail */
+               if (reset || err) {
+                       tty_ldisc_reinit(tty, N_TTY);
+                       WARN_ON(tty_ldisc_open(tty, tty->ldisc));
+               }
+               tty_ldisc_enable(tty);
+       }
+       mutex_unlock(&tty->ldisc_mutex);
+       if (reset)
+               tty_reset_termios(tty);
+}
+
+/**
+ *     tty_ldisc_setup                 -       open line discipline
+ *     @tty: tty being shut down
+ *     @o_tty: pair tty for pty/tty pairs
+ *
+ *     Called during the initial open of a tty/pty pair in order to set up the
+ *     line disciplines and bind them to the tty. This has no locking issues
+ *     as the device isn't yet active.
+ */
+
+int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
+{
+       struct tty_ldisc *ld = tty->ldisc;
+       int retval;
+
+       retval = tty_ldisc_open(tty, ld);
+       if (retval)
+               return retval;
+
+       if (o_tty) {
+               retval = tty_ldisc_open(o_tty, o_tty->ldisc);
+               if (retval) {
+                       tty_ldisc_close(tty, ld);
+                       return retval;
+               }
+               tty_ldisc_enable(o_tty);
+       }
+       tty_ldisc_enable(tty);
+       return 0;
+}
+/**
+ *     tty_ldisc_release               -       release line discipline
+ *     @tty: tty being shut down
+ *     @o_tty: pair tty for pty/tty pairs
+ *
+ *     Called during the final close of a tty/pty pair in order to shut down
+ *     the line discpline layer. On exit the ldisc assigned is N_TTY and the
+ *     ldisc has not been opened.
+ */
+
+void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
+{
+       /*
+        * Prevent flush_to_ldisc() from rescheduling the work for later.  Then
+        * kill any delayed work. As this is the final close it does not
+        * race with the set_ldisc code path.
+        */
+
+       tty_unlock();
+       tty_ldisc_halt(tty);
+       flush_scheduled_work();
+       tty_lock();
+
+       mutex_lock(&tty->ldisc_mutex);
+       /*
+        * Now kill off the ldisc
+        */
+       tty_ldisc_close(tty, tty->ldisc);
+       tty_ldisc_put(tty->ldisc);
+       /* Force an oops if we mess this up */
+       tty->ldisc = NULL;
+
+       /* Ensure the next open requests the N_TTY ldisc */
+       tty_set_termios_ldisc(tty, N_TTY);
+       mutex_unlock(&tty->ldisc_mutex);
+
+       /* This will need doing differently if we need to lock */
+       if (o_tty)
+               tty_ldisc_release(o_tty, NULL);
+
+       /* And the memory resources remaining (buffers, termios) will be
+          disposed of when the kref hits zero */
+}
+
+/**
+ *     tty_ldisc_init          -       ldisc setup for new tty
+ *     @tty: tty being allocated
+ *
+ *     Set up the line discipline objects for a newly allocated tty. Note that
+ *     the tty structure is not completely set up when this call is made.
+ */
+
+void tty_ldisc_init(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
+       if (IS_ERR(ld))
+               panic("n_tty: init_tty");
+       tty_ldisc_assign(tty, ld);
+}
+
+void tty_ldisc_begin(void)
+{
+       /* Setup the default TTY line discipline. */
+       (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
+}
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c
new file mode 100644 (file)
index 0000000..1336975
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * drivers/char/tty_lock.c
+ */
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/semaphore.h>
+#include <linux/sched.h>
+
+/*
+ * The 'big tty mutex'
+ *
+ * This mutex is taken and released by tty_lock() and tty_unlock(),
+ * replacing the older big kernel lock.
+ * It can no longer be taken recursively, and does not get
+ * released implicitly while sleeping.
+ *
+ * Don't use in new code.
+ */
+static DEFINE_MUTEX(big_tty_mutex);
+struct task_struct *__big_tty_mutex_owner;
+EXPORT_SYMBOL_GPL(__big_tty_mutex_owner);
+
+/*
+ * Getting the big tty mutex.
+ */
+void __lockfunc tty_lock(void)
+{
+       struct task_struct *task = current;
+
+       WARN_ON(__big_tty_mutex_owner == task);
+
+       mutex_lock(&big_tty_mutex);
+       __big_tty_mutex_owner = task;
+}
+EXPORT_SYMBOL(tty_lock);
+
+void __lockfunc tty_unlock(void)
+{
+       struct task_struct *task = current;
+
+       WARN_ON(__big_tty_mutex_owner != task);
+       __big_tty_mutex_owner = NULL;
+
+       mutex_unlock(&big_tty_mutex);
+}
+EXPORT_SYMBOL(tty_unlock);
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
new file mode 100644 (file)
index 0000000..33d37d2
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * Tty port functions
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+void tty_port_init(struct tty_port *port)
+{
+       memset(port, 0, sizeof(*port));
+       init_waitqueue_head(&port->open_wait);
+       init_waitqueue_head(&port->close_wait);
+       init_waitqueue_head(&port->delta_msr_wait);
+       mutex_init(&port->mutex);
+       mutex_init(&port->buf_mutex);
+       spin_lock_init(&port->lock);
+       port->close_delay = (50 * HZ) / 100;
+       port->closing_wait = (3000 * HZ) / 100;
+       kref_init(&port->kref);
+}
+EXPORT_SYMBOL(tty_port_init);
+
+int tty_port_alloc_xmit_buf(struct tty_port *port)
+{
+       /* We may sleep in get_zeroed_page() */
+       mutex_lock(&port->buf_mutex);
+       if (port->xmit_buf == NULL)
+               port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
+       mutex_unlock(&port->buf_mutex);
+       if (port->xmit_buf == NULL)
+               return -ENOMEM;
+       return 0;
+}
+EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
+
+void tty_port_free_xmit_buf(struct tty_port *port)
+{
+       mutex_lock(&port->buf_mutex);
+       if (port->xmit_buf != NULL) {
+               free_page((unsigned long)port->xmit_buf);
+               port->xmit_buf = NULL;
+       }
+       mutex_unlock(&port->buf_mutex);
+}
+EXPORT_SYMBOL(tty_port_free_xmit_buf);
+
+static void tty_port_destructor(struct kref *kref)
+{
+       struct tty_port *port = container_of(kref, struct tty_port, kref);
+       if (port->xmit_buf)
+               free_page((unsigned long)port->xmit_buf);
+       if (port->ops->destruct)
+               port->ops->destruct(port);
+       else
+               kfree(port);
+}
+
+void tty_port_put(struct tty_port *port)
+{
+       if (port)
+               kref_put(&port->kref, tty_port_destructor);
+}
+EXPORT_SYMBOL(tty_port_put);
+
+/**
+ *     tty_port_tty_get        -       get a tty reference
+ *     @port: tty port
+ *
+ *     Return a refcount protected tty instance or NULL if the port is not
+ *     associated with a tty (eg due to close or hangup)
+ */
+
+struct tty_struct *tty_port_tty_get(struct tty_port *port)
+{
+       unsigned long flags;
+       struct tty_struct *tty;
+
+       spin_lock_irqsave(&port->lock, flags);
+       tty = tty_kref_get(port->tty);
+       spin_unlock_irqrestore(&port->lock, flags);
+       return tty;
+}
+EXPORT_SYMBOL(tty_port_tty_get);
+
+/**
+ *     tty_port_tty_set        -       set the tty of a port
+ *     @port: tty port
+ *     @tty: the tty
+ *
+ *     Associate the port and tty pair. Manages any internal refcounts.
+ *     Pass NULL to deassociate a port
+ */
+
+void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (port->tty)
+               tty_kref_put(port->tty);
+       port->tty = tty_kref_get(tty);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL(tty_port_tty_set);
+
+static void tty_port_shutdown(struct tty_port *port)
+{
+       mutex_lock(&port->mutex);
+       if (port->ops->shutdown && !port->console &&
+               test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
+                       port->ops->shutdown(port);
+       mutex_unlock(&port->mutex);
+}
+
+/**
+ *     tty_port_hangup         -       hangup helper
+ *     @port: tty port
+ *
+ *     Perform port level tty hangup flag and count changes. Drop the tty
+ *     reference.
+ */
+
+void tty_port_hangup(struct tty_port *port)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       port->count = 0;
+       port->flags &= ~ASYNC_NORMAL_ACTIVE;
+       if (port->tty) {
+               set_bit(TTY_IO_ERROR, &port->tty->flags);
+               tty_kref_put(port->tty);
+       }
+       port->tty = NULL;
+       spin_unlock_irqrestore(&port->lock, flags);
+       wake_up_interruptible(&port->open_wait);
+       wake_up_interruptible(&port->delta_msr_wait);
+       tty_port_shutdown(port);
+}
+EXPORT_SYMBOL(tty_port_hangup);
+
+/**
+ *     tty_port_carrier_raised -       carrier raised check
+ *     @port: tty port
+ *
+ *     Wrapper for the carrier detect logic. For the moment this is used
+ *     to hide some internal details. This will eventually become entirely
+ *     internal to the tty port.
+ */
+
+int tty_port_carrier_raised(struct tty_port *port)
+{
+       if (port->ops->carrier_raised == NULL)
+               return 1;
+       return port->ops->carrier_raised(port);
+}
+EXPORT_SYMBOL(tty_port_carrier_raised);
+
+/**
+ *     tty_port_raise_dtr_rts  -       Raise DTR/RTS
+ *     @port: tty port
+ *
+ *     Wrapper for the DTR/RTS raise logic. For the moment this is used
+ *     to hide some internal details. This will eventually become entirely
+ *     internal to the tty port.
+ */
+
+void tty_port_raise_dtr_rts(struct tty_port *port)
+{
+       if (port->ops->dtr_rts)
+               port->ops->dtr_rts(port, 1);
+}
+EXPORT_SYMBOL(tty_port_raise_dtr_rts);
+
+/**
+ *     tty_port_lower_dtr_rts  -       Lower DTR/RTS
+ *     @port: tty port
+ *
+ *     Wrapper for the DTR/RTS raise logic. For the moment this is used
+ *     to hide some internal details. This will eventually become entirely
+ *     internal to the tty port.
+ */
+
+void tty_port_lower_dtr_rts(struct tty_port *port)
+{
+       if (port->ops->dtr_rts)
+               port->ops->dtr_rts(port, 0);
+}
+EXPORT_SYMBOL(tty_port_lower_dtr_rts);
+
+/**
+ *     tty_port_block_til_ready        -       Waiting logic for tty open
+ *     @port: the tty port being opened
+ *     @tty: the tty device being bound
+ *     @filp: the file pointer of the opener
+ *
+ *     Implement the core POSIX/SuS tty behaviour when opening a tty device.
+ *     Handles:
+ *             - hangup (both before and during)
+ *             - non blocking open
+ *             - rts/dtr/dcd
+ *             - signals
+ *             - port flags and counts
+ *
+ *     The passed tty_port must implement the carrier_raised method if it can
+ *     do carrier detect and the dtr_rts method if it supports software
+ *     management of these lines. Note that the dtr/rts raise is done each
+ *     iteration as a hangup may have previously dropped them while we wait.
+ */
+
+int tty_port_block_til_ready(struct tty_port *port,
+                               struct tty_struct *tty, struct file *filp)
+{
+       int do_clocal = 0, retval;
+       unsigned long flags;
+       DEFINE_WAIT(wait);
+       int cd;
+
+       /* block if port is in the process of being closed */
+       if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+               wait_event_interruptible_tty(port->close_wait,
+                               !(port->flags & ASYNC_CLOSING));
+               if (port->flags & ASYNC_HUP_NOTIFY)
+                       return -EAGAIN;
+               else
+                       return -ERESTARTSYS;
+       }
+
+       /* if non-blocking mode is set we can pass directly to open unless
+          the port has just hung up or is in another error state */
+       if (tty->flags & (1 << TTY_IO_ERROR)) {
+               port->flags |= ASYNC_NORMAL_ACTIVE;
+               return 0;
+       }
+       if (filp->f_flags & O_NONBLOCK) {
+               /* Indicate we are open */
+               if (tty->termios->c_cflag & CBAUD)
+                       tty_port_raise_dtr_rts(port);
+               port->flags |= ASYNC_NORMAL_ACTIVE;
+               return 0;
+       }
+
+       if (C_CLOCAL(tty))
+               do_clocal = 1;
+
+       /* Block waiting until we can proceed. We may need to wait for the
+          carrier, but we must also wait for any close that is in progress
+          before the next open may complete */
+
+       retval = 0;
+
+       /* The port lock protects the port counts */
+       spin_lock_irqsave(&port->lock, flags);
+       if (!tty_hung_up_p(filp))
+               port->count--;
+       port->blocked_open++;
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       while (1) {
+               /* Indicate we are open */
+               if (tty->termios->c_cflag & CBAUD)
+                       tty_port_raise_dtr_rts(port);
+
+               prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
+               /* Check for a hangup or uninitialised port.
+                                                       Return accordingly */
+               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
+                       if (port->flags & ASYNC_HUP_NOTIFY)
+                               retval = -EAGAIN;
+                       else
+                               retval = -ERESTARTSYS;
+                       break;
+               }
+               /* Probe the carrier. For devices with no carrier detect this
+                  will always return true */
+               cd = tty_port_carrier_raised(port);
+               if (!(port->flags & ASYNC_CLOSING) &&
+                               (do_clocal || cd))
+                       break;
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+               tty_unlock();
+               schedule();
+               tty_lock();
+       }
+       finish_wait(&port->open_wait, &wait);
+
+       /* Update counts. A parallel hangup will have set count to zero and
+          we must not mess that up further */
+       spin_lock_irqsave(&port->lock, flags);
+       if (!tty_hung_up_p(filp))
+               port->count++;
+       port->blocked_open--;
+       if (retval == 0)
+               port->flags |= ASYNC_NORMAL_ACTIVE;
+       spin_unlock_irqrestore(&port->lock, flags);
+       return retval;
+}
+EXPORT_SYMBOL(tty_port_block_til_ready);
+
+int tty_port_close_start(struct tty_port *port,
+                               struct tty_struct *tty, struct file *filp)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (tty_hung_up_p(filp)) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               return 0;
+       }
+
+       if (tty->count == 1 && port->count != 1) {
+               printk(KERN_WARNING
+                   "tty_port_close_start: tty->count = 1 port count = %d.\n",
+                                                               port->count);
+               port->count = 1;
+       }
+       if (--port->count < 0) {
+               printk(KERN_WARNING "tty_port_close_start: count = %d\n",
+                                                               port->count);
+               port->count = 0;
+       }
+
+       if (port->count) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               if (port->ops->drop)
+                       port->ops->drop(port);
+               return 0;
+       }
+       set_bit(ASYNCB_CLOSING, &port->flags);
+       tty->closing = 1;
+       spin_unlock_irqrestore(&port->lock, flags);
+       /* Don't block on a stalled port, just pull the chain */
+       if (tty->flow_stopped)
+               tty_driver_flush_buffer(tty);
+       if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
+                       port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, port->closing_wait);
+       if (port->drain_delay) {
+               unsigned int bps = tty_get_baud_rate(tty);
+               long timeout;
+
+               if (bps > 1200)
+                       timeout = max_t(long,
+                               (HZ * 10 * port->drain_delay) / bps, HZ / 10);
+               else
+                       timeout = 2 * HZ;
+               schedule_timeout_interruptible(timeout);
+       }
+       /* Flush the ldisc buffering */
+       tty_ldisc_flush(tty);
+
+       /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
+          hang up the line */
+       if (tty->termios->c_cflag & HUPCL)
+               tty_port_lower_dtr_rts(port);
+
+       /* Don't call port->drop for the last reference. Callers will want
+          to drop the last active reference in ->shutdown() or the tty
+          shutdown path */
+       return 1;
+}
+EXPORT_SYMBOL(tty_port_close_start);
+
+void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       tty->closing = 0;
+
+       if (port->blocked_open) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               if (port->close_delay) {
+                       msleep_interruptible(
+                               jiffies_to_msecs(port->close_delay));
+               }
+               spin_lock_irqsave(&port->lock, flags);
+               wake_up_interruptible(&port->open_wait);
+       }
+       port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+       wake_up_interruptible(&port->close_wait);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL(tty_port_close_end);
+
+void tty_port_close(struct tty_port *port, struct tty_struct *tty,
+                                                       struct file *filp)
+{
+       if (tty_port_close_start(port, tty, filp) == 0)
+               return;
+       tty_port_shutdown(port);
+       set_bit(TTY_IO_ERROR, &tty->flags);
+       tty_port_close_end(port, tty);
+       tty_port_tty_set(port, NULL);
+}
+EXPORT_SYMBOL(tty_port_close);
+
+int tty_port_open(struct tty_port *port, struct tty_struct *tty,
+                                                       struct file *filp)
+{
+       spin_lock_irq(&port->lock);
+       if (!tty_hung_up_p(filp))
+               ++port->count;
+       spin_unlock_irq(&port->lock);
+       tty_port_tty_set(port, tty);
+
+       /*
+        * Do the device-specific open only if the hardware isn't
+        * already initialized. Serialize open and shutdown using the
+        * port mutex.
+        */
+
+       mutex_lock(&port->mutex);
+
+       if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+               clear_bit(TTY_IO_ERROR, &tty->flags);
+               if (port->ops->activate) {
+                       int retval = port->ops->activate(port, tty);
+                       if (retval) {
+                               mutex_unlock(&port->mutex);
+                               return retval;
+                       }
+               }
+               set_bit(ASYNCB_INITIALIZED, &port->flags);
+       }
+       mutex_unlock(&port->mutex);
+       return tty_port_block_til_ready(port, tty, filp);
+}
+
+EXPORT_SYMBOL(tty_port_open);
diff --git a/drivers/tty/vt/.gitignore b/drivers/tty/vt/.gitignore
new file mode 100644 (file)
index 0000000..83683a2
--- /dev/null
@@ -0,0 +1,2 @@
+consolemap_deftbl.c
+defkeymap.c
diff --git a/drivers/tty/vt/Makefile b/drivers/tty/vt/Makefile
new file mode 100644 (file)
index 0000000..14a51c9
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# This file contains the font map for the default (hardware) font
+#
+FONTMAPFILE = cp437.uni
+
+obj-$(CONFIG_VT)                       += vt_ioctl.o vc_screen.o \
+                                          selection.o keyboard.o
+obj-$(CONFIG_CONSOLE_TRANSLATIONS)     += consolemap.o consolemap_deftbl.o
+obj-$(CONFIG_HW_CONSOLE)               += vt.o defkeymap.o
+
+# Files generated that shall be removed upon make clean
+clean-files := consolemap_deftbl.c defkeymap.c
+
+quiet_cmd_conmk = CONMK   $@
+      cmd_conmk = scripts/conmakehash $< > $@
+
+$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE)
+       $(call cmd,conmk)
+
+$(obj)/defkeymap.o:  $(obj)/defkeymap.c
+
+# Uncomment if you're changing the keymap and have an appropriate
+# loadkeys version for the map. By default, we'll use the shipped
+# versions.
+# GENERATE_KEYMAP := 1
+
+ifdef GENERATE_KEYMAP
+
+$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
+       loadkeys --mktable $< > $@.tmp
+       sed -e 's/^static *//' $@.tmp > $@
+       rm $@.tmp
+
+endif
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
new file mode 100644 (file)
index 0000000..45d3e80
--- /dev/null
@@ -0,0 +1,745 @@
+/*
+ * consolemap.c
+ *
+ * Mapping from internal code (such as Latin-1 or Unicode or IBM PC code)
+ * to font positions.
+ *
+ * aeb, 950210
+ *
+ * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998
+ *
+ * Fix bug in inverse translation. Stanislav Voronyi <stas@cnti.uanet.kharkov.ua>, Dec 1998
+ */
+
+#include <linux/module.h>
+#include <linux/kd.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <asm/uaccess.h>
+#include <linux/consolemap.h>
+#include <linux/vt_kern.h>
+
+static unsigned short translations[][256] = {
+  /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
+  {
+    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+    0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+    0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
+    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+    0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+    0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
+    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
+    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
+    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+    0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+    0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+    0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
+    0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+    0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+    0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
+  }, 
+  /* VT100 graphics mapped to Unicode */
+  {
+    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+    0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+    0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
+    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+    0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
+    0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
+    0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
+    0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
+    0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
+    0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
+    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
+    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
+    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+    0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+    0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+    0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
+    0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+    0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+    0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
+  },
+  /* IBM Codepage 437 mapped to Unicode */
+  {
+    0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 
+    0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
+    0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
+    0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
+    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+    0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+    0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
+    0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
+    0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
+    0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
+    0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
+    0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
+    0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+    0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
+    0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
+    0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
+    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
+    0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
+    0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
+    0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
+    0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
+    0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
+  }, 
+  /* User mapping -- default to codes for direct font mapping */
+  {
+    0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007,
+    0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f,
+    0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017,
+    0xf018, 0xf019, 0xf01a, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
+    0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027,
+    0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02d, 0xf02e, 0xf02f,
+    0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
+    0xf038, 0xf039, 0xf03a, 0xf03b, 0xf03c, 0xf03d, 0xf03e, 0xf03f,
+    0xf040, 0xf041, 0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047,
+    0xf048, 0xf049, 0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f,
+    0xf050, 0xf051, 0xf052, 0xf053, 0xf054, 0xf055, 0xf056, 0xf057,
+    0xf058, 0xf059, 0xf05a, 0xf05b, 0xf05c, 0xf05d, 0xf05e, 0xf05f,
+    0xf060, 0xf061, 0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067,
+    0xf068, 0xf069, 0xf06a, 0xf06b, 0xf06c, 0xf06d, 0xf06e, 0xf06f,
+    0xf070, 0xf071, 0xf072, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077,
+    0xf078, 0xf079, 0xf07a, 0xf07b, 0xf07c, 0xf07d, 0xf07e, 0xf07f,
+    0xf080, 0xf081, 0xf082, 0xf083, 0xf084, 0xf085, 0xf086, 0xf087,
+    0xf088, 0xf089, 0xf08a, 0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f,
+    0xf090, 0xf091, 0xf092, 0xf093, 0xf094, 0xf095, 0xf096, 0xf097,
+    0xf098, 0xf099, 0xf09a, 0xf09b, 0xf09c, 0xf09d, 0xf09e, 0xf09f,
+    0xf0a0, 0xf0a1, 0xf0a2, 0xf0a3, 0xf0a4, 0xf0a5, 0xf0a6, 0xf0a7,
+    0xf0a8, 0xf0a9, 0xf0aa, 0xf0ab, 0xf0ac, 0xf0ad, 0xf0ae, 0xf0af,
+    0xf0b0, 0xf0b1, 0xf0b2, 0xf0b3, 0xf0b4, 0xf0b5, 0xf0b6, 0xf0b7,
+    0xf0b8, 0xf0b9, 0xf0ba, 0xf0bb, 0xf0bc, 0xf0bd, 0xf0be, 0xf0bf,
+    0xf0c0, 0xf0c1, 0xf0c2, 0xf0c3, 0xf0c4, 0xf0c5, 0xf0c6, 0xf0c7,
+    0xf0c8, 0xf0c9, 0xf0ca, 0xf0cb, 0xf0cc, 0xf0cd, 0xf0ce, 0xf0cf,
+    0xf0d0, 0xf0d1, 0xf0d2, 0xf0d3, 0xf0d4, 0xf0d5, 0xf0d6, 0xf0d7,
+    0xf0d8, 0xf0d9, 0xf0da, 0xf0db, 0xf0dc, 0xf0dd, 0xf0de, 0xf0df,
+    0xf0e0, 0xf0e1, 0xf0e2, 0xf0e3, 0xf0e4, 0xf0e5, 0xf0e6, 0xf0e7,
+    0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef,
+    0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7,
+    0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff
+  }
+};
+
+/* The standard kernel character-to-font mappings are not invertible
+   -- this is just a best effort. */
+
+#define MAX_GLYPH 512          /* Max possible glyph value */
+
+static int inv_translate[MAX_NR_CONSOLES];
+
+struct uni_pagedir {
+       u16             **uni_pgdir[32];
+       unsigned long   refcount;
+       unsigned long   sum;
+       unsigned char   *inverse_translations[4];
+       u16             *inverse_trans_unicode;
+       int             readonly;
+};
+
+static struct uni_pagedir *dflt;
+
+static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i)
+{
+       int j, glyph;
+       unsigned short *t = translations[i];
+       unsigned char *q;
+       
+       if (!p) return;
+       q = p->inverse_translations[i];
+
+       if (!q) {
+               q = p->inverse_translations[i] = (unsigned char *) 
+                       kmalloc(MAX_GLYPH, GFP_KERNEL);
+               if (!q) return;
+       }
+       memset(q, 0, MAX_GLYPH);
+
+       for (j = 0; j < E_TABSZ; j++) {
+               glyph = conv_uni_to_pc(conp, t[j]);
+               if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) {
+                       /* prefer '-' above SHY etc. */
+                       q[glyph] = j;
+               }
+       }
+}
+
+static void set_inverse_trans_unicode(struct vc_data *conp,
+                                     struct uni_pagedir *p)
+{
+       int i, j, k, glyph;
+       u16 **p1, *p2;
+       u16 *q;
+
+       if (!p) return;
+       q = p->inverse_trans_unicode;
+       if (!q) {
+               q = p->inverse_trans_unicode =
+                       kmalloc(MAX_GLYPH * sizeof(u16), GFP_KERNEL);
+               if (!q)
+                       return;
+       }
+       memset(q, 0, MAX_GLYPH * sizeof(u16));
+
+       for (i = 0; i < 32; i++) {
+               p1 = p->uni_pgdir[i];
+               if (!p1)
+                       continue;
+               for (j = 0; j < 32; j++) {
+                       p2 = p1[j];
+                       if (!p2)
+                               continue;
+                       for (k = 0; k < 64; k++) {
+                               glyph = p2[k];
+                               if (glyph >= 0 && glyph < MAX_GLYPH
+                                              && q[glyph] < 32)
+                                       q[glyph] = (i << 11) + (j << 6) + k;
+                       }
+               }
+       }
+}
+
+unsigned short *set_translate(int m, struct vc_data *vc)
+{
+       inv_translate[vc->vc_num] = m;
+       return translations[m];
+}
+
+/*
+ * Inverse translation is impossible for several reasons:
+ * 1. The font<->character maps are not 1-1.
+ * 2. The text may have been written while a different translation map
+ *    was active.
+ * Still, it is now possible to a certain extent to cut and paste non-ASCII.
+ */
+u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
+{
+       struct uni_pagedir *p;
+       int m;
+       if (glyph < 0 || glyph >= MAX_GLYPH)
+               return 0;
+       else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
+               return glyph;
+       else if (use_unicode) {
+               if (!p->inverse_trans_unicode)
+                       return glyph;
+               else
+                       return p->inverse_trans_unicode[glyph];
+       } else {
+               m = inv_translate[conp->vc_num];
+               if (!p->inverse_translations[m])
+                       return glyph;
+               else
+                       return p->inverse_translations[m][glyph];
+       }
+}
+EXPORT_SYMBOL_GPL(inverse_translate);
+
+static void update_user_maps(void)
+{
+       int i;
+       struct uni_pagedir *p, *q = NULL;
+       
+       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               if (!vc_cons_allocated(i))
+                       continue;
+               p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+               if (p && p != q) {
+                       set_inverse_transl(vc_cons[i].d, p, USER_MAP);
+                       set_inverse_trans_unicode(vc_cons[i].d, p);
+                       q = p;
+               }
+       }
+}
+
+/*
+ * Load customizable translation table
+ * arg points to a 256 byte translation table.
+ *
+ * The "old" variants are for translation directly to font (using the
+ * 0xf000-0xf0ff "transparent" Unicodes) whereas the "new" variants set
+ * Unicodes explicitly.
+ */
+int con_set_trans_old(unsigned char __user * arg)
+{
+       int i;
+       unsigned short *p = translations[USER_MAP];
+
+       if (!access_ok(VERIFY_READ, arg, E_TABSZ))
+               return -EFAULT;
+
+       for (i=0; i<E_TABSZ ; i++) {
+               unsigned char uc;
+               __get_user(uc, arg+i);
+               p[i] = UNI_DIRECT_BASE | uc;
+       }
+
+       update_user_maps();
+       return 0;
+}
+
+int con_get_trans_old(unsigned char __user * arg)
+{
+       int i, ch;
+       unsigned short *p = translations[USER_MAP];
+
+       if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
+               return -EFAULT;
+
+       for (i=0; i<E_TABSZ ; i++)
+         {
+           ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
+           __put_user((ch & ~0xff) ? 0 : ch, arg+i);
+         }
+       return 0;
+}
+
+int con_set_trans_new(ushort __user * arg)
+{
+       int i;
+       unsigned short *p = translations[USER_MAP];
+
+       if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
+               return -EFAULT;
+
+       for (i=0; i<E_TABSZ ; i++) {
+               unsigned short us;
+               __get_user(us, arg+i);
+               p[i] = us;
+       }
+
+       update_user_maps();
+       return 0;
+}
+
+int con_get_trans_new(ushort __user * arg)
+{
+       int i;
+       unsigned short *p = translations[USER_MAP];
+
+       if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
+               return -EFAULT;
+
+       for (i=0; i<E_TABSZ ; i++)
+         __put_user(p[i], arg+i);
+       
+       return 0;
+}
+
+/*
+ * Unicode -> current font conversion 
+ *
+ * A font has at most 512 chars, usually 256.
+ * But one font position may represent several Unicode chars.
+ * A hashtable is somewhat of a pain to deal with, so use a
+ * "paged table" instead.  Simulation has shown the memory cost of
+ * this 3-level paged table scheme to be comparable to a hash table.
+ */
+
+extern u8 dfont_unicount[];    /* Defined in console_defmap.c */
+extern u16 dfont_unitable[];
+
+static void con_release_unimap(struct uni_pagedir *p)
+{
+       u16 **p1;
+       int i, j;
+
+       if (p == dflt) dflt = NULL;  
+       for (i = 0; i < 32; i++) {
+               if ((p1 = p->uni_pgdir[i]) != NULL) {
+                       for (j = 0; j < 32; j++)
+                               kfree(p1[j]);
+                       kfree(p1);
+               }
+               p->uni_pgdir[i] = NULL;
+       }
+       for (i = 0; i < 4; i++) {
+               kfree(p->inverse_translations[i]);
+               p->inverse_translations[i] = NULL;
+       }
+       if (p->inverse_trans_unicode) {
+               kfree(p->inverse_trans_unicode);
+               p->inverse_trans_unicode = NULL;
+       }
+}
+
+void con_free_unimap(struct vc_data *vc)
+{
+       struct uni_pagedir *p;
+
+       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+       if (!p)
+               return;
+       *vc->vc_uni_pagedir_loc = 0;
+       if (--p->refcount)
+               return;
+       con_release_unimap(p);
+       kfree(p);
+}
+  
+static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
+{
+       int i, j, k;
+       struct uni_pagedir *q;
+       
+       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               if (!vc_cons_allocated(i))
+                       continue;
+               q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+               if (!q || q == p || q->sum != p->sum)
+                       continue;
+               for (j = 0; j < 32; j++) {
+                       u16 **p1, **q1;
+                       p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
+                       if (!p1 && !q1)
+                               continue;
+                       if (!p1 || !q1)
+                               break;
+                       for (k = 0; k < 32; k++) {
+                               if (!p1[k] && !q1[k])
+                                       continue;
+                               if (!p1[k] || !q1[k])
+                                       break;
+                               if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
+                                       break;
+                       }
+                       if (k < 32)
+                               break;
+               }
+               if (j == 32) {
+                       q->refcount++;
+                       *conp->vc_uni_pagedir_loc = (unsigned long)q;
+                       con_release_unimap(p);
+                       kfree(p);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static int
+con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
+{
+       int i, n;
+       u16 **p1, *p2;
+
+       if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
+               p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
+               if (!p1) return -ENOMEM;
+               for (i = 0; i < 32; i++)
+                       p1[i] = NULL;
+       }
+
+       if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
+               p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
+               if (!p2) return -ENOMEM;
+               memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
+       }
+
+       p2[unicode & 0x3f] = fontpos;
+       
+       p->sum += (fontpos << 20) + unicode;
+
+       return 0;
+}
+
+/* ui is a leftover from using a hashtable, but might be used again */
+int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
+{
+       struct uni_pagedir *p, *q;
+  
+       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+       if (p && p->readonly) return -EIO;
+       if (!p || --p->refcount) {
+               q = kzalloc(sizeof(*p), GFP_KERNEL);
+               if (!q) {
+                       if (p) p->refcount++;
+                       return -ENOMEM;
+               }
+               q->refcount=1;
+               *vc->vc_uni_pagedir_loc = (unsigned long)q;
+       } else {
+               if (p == dflt) dflt = NULL;
+               p->refcount++;
+               p->sum = 0;
+               con_release_unimap(p);
+       }
+       return 0;
+}
+
+int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
+{
+       int err = 0, err1, i;
+       struct uni_pagedir *p, *q;
+
+       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+       if (p->readonly) return -EIO;
+       
+       if (!ct) return 0;
+       
+       if (p->refcount > 1) {
+               int j, k;
+               u16 **p1, *p2, l;
+               
+               err1 = con_clear_unimap(vc, NULL);
+               if (err1) return err1;
+               
+               q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+               for (i = 0, l = 0; i < 32; i++)
+               if ((p1 = p->uni_pgdir[i]))
+                       for (j = 0; j < 32; j++)
+                       if ((p2 = p1[j]))
+                               for (k = 0; k < 64; k++, l++)
+                               if (p2[k] != 0xffff) {
+                                       err1 = con_insert_unipair(q, l, p2[k]);
+                                       if (err1) {
+                                               p->refcount++;
+                                               *vc->vc_uni_pagedir_loc = (unsigned long)p;
+                                               con_release_unimap(q);
+                                               kfree(q);
+                                               return err1; 
+                                       }
+                               }
+               p = q;
+       } else if (p == dflt)
+               dflt = NULL;
+       
+       while (ct--) {
+               unsigned short unicode, fontpos;
+               __get_user(unicode, &list->unicode);
+               __get_user(fontpos, &list->fontpos);
+               if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
+                       err = err1;
+               list++;
+       }
+       
+       if (con_unify_unimap(vc, p))
+               return err;
+
+       for (i = 0; i <= 3; i++)
+               set_inverse_transl(vc, p, i); /* Update all inverse translations */
+       set_inverse_trans_unicode(vc, p);
+  
+       return err;
+}
+
+/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
+   The representation used was the most compact I could come up
+   with.  This routine is executed at sys_setup time, and when the
+   PIO_FONTRESET ioctl is called. */
+
+int con_set_default_unimap(struct vc_data *vc)
+{
+       int i, j, err = 0, err1;
+       u16 *q;
+       struct uni_pagedir *p;
+
+       if (dflt) {
+               p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+               if (p == dflt)
+                       return 0;
+               dflt->refcount++;
+               *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
+               if (p && --p->refcount) {
+                       con_release_unimap(p);
+                       kfree(p);
+               }
+               return 0;
+       }
+       
+       /* The default font is always 256 characters */
+
+       err = con_clear_unimap(vc, NULL);
+       if (err) return err;
+    
+       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+       q = dfont_unitable;
+       
+       for (i = 0; i < 256; i++)
+               for (j = dfont_unicount[i]; j; j--) {
+                       err1 = con_insert_unipair(p, *(q++), i);
+                       if (err1)
+                               err = err1;
+               }
+                       
+       if (con_unify_unimap(vc, p)) {
+               dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+               return err;
+       }
+
+       for (i = 0; i <= 3; i++)
+               set_inverse_transl(vc, p, i);   /* Update all inverse translations */
+       set_inverse_trans_unicode(vc, p);
+       dflt = p;
+       return err;
+}
+EXPORT_SYMBOL(con_set_default_unimap);
+
+int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
+{
+       struct uni_pagedir *q;
+
+       if (!*src_vc->vc_uni_pagedir_loc)
+               return -EINVAL;
+       if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
+               return 0;
+       con_free_unimap(dst_vc);
+       q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
+       q->refcount++;
+       *dst_vc->vc_uni_pagedir_loc = (long)q;
+       return 0;
+}
+
+int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
+{
+       int i, j, k, ect;
+       u16 **p1, *p2;
+       struct uni_pagedir *p;
+
+       ect = 0;
+       if (*vc->vc_uni_pagedir_loc) {
+               p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+               for (i = 0; i < 32; i++)
+               if ((p1 = p->uni_pgdir[i]))
+                       for (j = 0; j < 32; j++)
+                       if ((p2 = *(p1++)))
+                               for (k = 0; k < 64; k++) {
+                                       if (*p2 < MAX_GLYPH && ect++ < ct) {
+                                               __put_user((u_short)((i<<11)+(j<<6)+k),
+                                                          &list->unicode);
+                                               __put_user((u_short) *p2, 
+                                                          &list->fontpos);
+                                               list++;
+                                       }
+                                       p2++;
+                               }
+       }
+       __put_user(ect, uct);
+       return ((ect <= ct) ? 0 : -ENOMEM);
+}
+
+void con_protect_unimap(struct vc_data *vc, int rdonly)
+{
+       struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+       
+       if (p)
+               p->readonly = rdonly;
+}
+
+/*
+ * Always use USER_MAP. These functions are used by the keyboard,
+ * which shouldn't be affected by G0/G1 switching, etc.
+ * If the user map still contains default values, i.e. the
+ * direct-to-font mapping, then assume user is using Latin1.
+ */
+/* may be called during an interrupt */
+u32 conv_8bit_to_uni(unsigned char c)
+{
+       unsigned short uni = translations[USER_MAP][c];
+       return uni == (0xf000 | c) ? c : uni;
+}
+
+int conv_uni_to_8bit(u32 uni)
+{
+       int c;
+       for (c = 0; c < 0x100; c++)
+               if (translations[USER_MAP][c] == uni ||
+                  (translations[USER_MAP][c] == (c | 0xf000) && uni == c))
+                       return c;
+       return -1;
+}
+
+int
+conv_uni_to_pc(struct vc_data *conp, long ucs) 
+{
+       int h;
+       u16 **p1, *p2;
+       struct uni_pagedir *p;
+  
+       /* Only 16-bit codes supported at this time */
+       if (ucs > 0xffff)
+               return -4;              /* Not found */
+       else if (ucs < 0x20)
+               return -1;              /* Not a printable character */
+       else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
+               return -2;                      /* Zero-width space */
+       /*
+        * UNI_DIRECT_BASE indicates the start of the region in the User Zone
+        * which always has a 1:1 mapping to the currently loaded font.  The
+        * UNI_DIRECT_MASK indicates the bit span of the region.
+        */
+       else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
+               return ucs & UNI_DIRECT_MASK;
+  
+       if (!*conp->vc_uni_pagedir_loc)
+               return -3;
+
+       p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;  
+       if ((p1 = p->uni_pgdir[ucs >> 11]) &&
+           (p2 = p1[(ucs >> 6) & 0x1f]) &&
+           (h = p2[ucs & 0x3f]) < MAX_GLYPH)
+               return h;
+
+       return -4;              /* not found */
+}
+
+/*
+ * This is called at sys_setup time, after memory and the console are
+ * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
+ * from this function, hence the call from sys_setup.
+ */
+void __init 
+console_map_init(void)
+{
+       int i;
+       
+       for (i = 0; i < MAX_NR_CONSOLES; i++)
+               if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
+                       con_set_default_unimap(vc_cons[i].d);
+}
+
+EXPORT_SYMBOL(con_copy_unimap);
diff --git a/drivers/tty/vt/cp437.uni b/drivers/tty/vt/cp437.uni
new file mode 100644 (file)
index 0000000..bc61634
--- /dev/null
@@ -0,0 +1,291 @@
+#
+# Unicode table for IBM Codepage 437.  Note that there are many more
+# substitutions that could be conceived (for example, thick-line
+# graphs probably should be replaced with double-line ones, accented
+# Latin characters should replaced with their nonaccented versions,
+# and some upper case Greek characters could be replaced by Latin), however,
+# I have limited myself to the Unicodes used by the kernel ISO 8859-1,
+# DEC VT, and IBM CP 437 tables.
+#
+# --------------------------------
+#
+# Basic IBM dingbats, some of which will never have a purpose clear
+# to mankind
+#
+0x00   U+0000
+0x01   U+263a
+0x02   U+263b
+0x03   U+2665
+0x04   U+2666 U+25c6
+0x05   U+2663
+0x06   U+2660
+0x07   U+2022
+0x08   U+25d8
+0x09   U+25cb
+0x0a   U+25d9
+0x0b   U+2642
+0x0c   U+2640
+0x0d   U+266a
+0x0e   U+266b
+0x0f   U+263c U+00a4
+0x10   U+25b6 U+25ba
+0x11   U+25c0 U+25c4
+0x12   U+2195
+0x13   U+203c
+0x14   U+00b6
+0x15   U+00a7
+0x16   U+25ac
+0x17   U+21a8
+0x18   U+2191
+0x19   U+2193
+0x1a   U+2192
+0x1b   U+2190
+0x1c   U+221f
+0x1d   U+2194
+0x1e   U+25b2
+0x1f   U+25bc
+#
+# The ASCII range is identity-mapped, but some of the characters also
+# have to act as substitutes, especially the upper-case characters.
+#
+0x20   U+0020
+0x21   U+0021
+0x22   U+0022 U+00a8
+0x23   U+0023
+0x24   U+0024
+0x25   U+0025
+0x26   U+0026
+0x27   U+0027 U+00b4
+0x28   U+0028
+0x29   U+0029
+0x2a   U+002a
+0x2b   U+002b
+0x2c   U+002c U+00b8
+0x2d   U+002d U+00ad
+0x2e   U+002e
+0x2f   U+002f
+0x30   U+0030
+0x31   U+0031
+0x32   U+0032
+0x33   U+0033
+0x34   U+0034
+0x35   U+0035
+0x36   U+0036
+0x37   U+0037
+0x38   U+0038
+0x39   U+0039
+0x3a   U+003a
+0x3b   U+003b
+0x3c   U+003c
+0x3d   U+003d
+0x3e   U+003e
+0x3f   U+003f
+0x40   U+0040
+0x41   U+0041 U+00c0 U+00c1 U+00c2 U+00c3
+0x42   U+0042
+0x43   U+0043 U+00a9
+0x44   U+0044 U+00d0
+0x45   U+0045 U+00c8 U+00ca U+00cb
+0x46   U+0046
+0x47   U+0047
+0x48   U+0048
+0x49   U+0049 U+00cc U+00cd U+00ce U+00cf
+0x4a   U+004a
+0x4b   U+004b U+212a
+0x4c   U+004c
+0x4d   U+004d
+0x4e   U+004e
+0x4f   U+004f U+00d2 U+00d3 U+00d4 U+00d5
+0x50   U+0050
+0x51   U+0051
+0x52   U+0052 U+00ae
+0x53   U+0053
+0x54   U+0054
+0x55   U+0055 U+00d9 U+00da U+00db
+0x56   U+0056
+0x57   U+0057
+0x58   U+0058
+0x59   U+0059 U+00dd
+0x5a   U+005a
+0x5b   U+005b
+0x5c   U+005c
+0x5d   U+005d
+0x5e   U+005e
+0x5f   U+005f U+23bd U+f804
+0x60   U+0060
+0x61   U+0061 U+00e3
+0x62   U+0062
+0x63   U+0063
+0x64   U+0064
+0x65   U+0065
+0x66   U+0066
+0x67   U+0067
+0x68   U+0068
+0x69   U+0069
+0x6a   U+006a
+0x6b   U+006b
+0x6c   U+006c
+0x6d   U+006d
+0x6e   U+006e
+0x6f   U+006f U+00f5
+0x70   U+0070
+0x71   U+0071
+0x72   U+0072
+0x73   U+0073
+0x74   U+0074
+0x75   U+0075
+0x76   U+0076
+0x77   U+0077
+0x78   U+0078 U+00d7
+0x79   U+0079 U+00fd
+0x7a   U+007a
+0x7b   U+007b
+0x7c   U+007c U+00a6
+0x7d   U+007d
+0x7e   U+007e
+#
+# Okay, what on Earth is this one supposed to be used for?
+#
+0x7f   U+2302
+#
+# Non-English characters, mostly lower case letters...
+#
+0x80   U+00c7
+0x81   U+00fc
+0x82   U+00e9
+0x83   U+00e2
+0x84   U+00e4
+0x85   U+00e0
+0x86   U+00e5
+0x87   U+00e7
+0x88   U+00ea
+0x89   U+00eb
+0x8a   U+00e8
+0x8b   U+00ef
+0x8c   U+00ee
+0x8d   U+00ec
+0x8e   U+00c4
+0x8f   U+00c5 U+212b
+0x90   U+00c9
+0x91   U+00e6
+0x92   U+00c6
+0x93   U+00f4
+0x94   U+00f6
+0x95   U+00f2
+0x96   U+00fb
+0x97   U+00f9
+0x98   U+00ff
+0x99   U+00d6
+0x9a   U+00dc
+0x9b   U+00a2
+0x9c   U+00a3
+0x9d   U+00a5
+0x9e   U+20a7
+0x9f   U+0192
+0xa0   U+00e1
+0xa1   U+00ed
+0xa2   U+00f3
+0xa3   U+00fa
+0xa4   U+00f1
+0xa5   U+00d1
+0xa6   U+00aa
+0xa7   U+00ba
+0xa8   U+00bf
+0xa9   U+2310
+0xaa   U+00ac
+0xab   U+00bd
+0xac   U+00bc
+0xad   U+00a1
+0xae   U+00ab
+0xaf   U+00bb
+#
+# Block graphics
+#
+0xb0   U+2591
+0xb1   U+2592
+0xb2   U+2593
+0xb3   U+2502
+0xb4   U+2524
+0xb5   U+2561
+0xb6   U+2562
+0xb7   U+2556
+0xb8   U+2555
+0xb9   U+2563
+0xba   U+2551
+0xbb   U+2557
+0xbc   U+255d
+0xbd   U+255c
+0xbe   U+255b
+0xbf   U+2510
+0xc0   U+2514
+0xc1   U+2534
+0xc2   U+252c
+0xc3   U+251c
+0xc4   U+2500
+0xc5   U+253c
+0xc6   U+255e
+0xc7   U+255f
+0xc8   U+255a
+0xc9   U+2554
+0xca   U+2569
+0xcb   U+2566
+0xcc   U+2560
+0xcd   U+2550
+0xce   U+256c
+0xcf   U+2567
+0xd0   U+2568
+0xd1   U+2564
+0xd2   U+2565
+0xd3   U+2559
+0xd4   U+2558
+0xd5   U+2552
+0xd6   U+2553
+0xd7   U+256b
+0xd8   U+256a
+0xd9   U+2518
+0xda   U+250c
+0xdb   U+2588
+0xdc   U+2584
+0xdd   U+258c
+0xde   U+2590
+0xdf   U+2580
+#
+# Greek letters and mathematical symbols
+#
+0xe0   U+03b1
+0xe1   U+03b2 U+00df
+0xe2   U+0393
+0xe3   U+03c0
+0xe4   U+03a3
+0xe5   U+03c3
+0xe6   U+00b5 U+03bc
+0xe7   U+03c4
+0xe8   U+03a6 U+00d8
+0xe9   U+0398
+0xea   U+03a9 U+2126
+0xeb   U+03b4 U+00f0
+0xec   U+221e
+0xed   U+03c6 U+00f8
+0xee   U+03b5 U+2208
+0xef   U+2229
+0xf0   U+2261
+0xf1   U+00b1
+0xf2   U+2265
+0xf3   U+2264
+0xf4   U+2320
+0xf5   U+2321
+0xf6   U+00f7
+0xf7   U+2248
+0xf8   U+00b0
+0xf9   U+2219
+0xfa   U+00b7
+0xfb   U+221a
+0xfc   U+207f
+0xfd   U+00b2
+#
+# Square bullet, non-spacing blank
+# Mapping U+fffd to the square bullet means it is the substitution
+# character
+# 
+0xfe   U+25a0 U+fffd
+0xff   U+00a0
diff --git a/drivers/tty/vt/defkeymap.c_shipped b/drivers/tty/vt/defkeymap.c_shipped
new file mode 100644 (file)
index 0000000..d2208df
--- /dev/null
@@ -0,0 +1,262 @@
+/* Do not edit this file! It was automatically generated by   */
+/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+u_short plain_map[NR_KEYS] = {
+       0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
+       0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf07f, 0xf009,
+       0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+       0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73,
+       0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
+       0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
+       0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf30c,
+       0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+       0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf209, 0xf307,
+       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03c, 0xf10a,
+       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short shift_map[NR_KEYS] = {
+       0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e,
+       0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07f, 0xf009,
+       0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
+       0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201, 0xf702, 0xfb41, 0xfb53,
+       0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a,
+       0xf022, 0xf07e, 0xf700, 0xf07c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56,
+       0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf30c,
+       0xf703, 0xf020, 0xf207, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e,
+       0xf10f, 0xf110, 0xf111, 0xf112, 0xf113, 0xf213, 0xf203, 0xf307,
+       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03e, 0xf10a,
+       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf20b, 0xf601, 0xf602, 0xf117, 0xf600, 0xf20a, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short altgr_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
+       0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200,
+       0xfb71, 0xfb77, 0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+       0xfb6f, 0xfb70, 0xf200, 0xf07e, 0xf201, 0xf702, 0xf914, 0xfb73,
+       0xf917, 0xf919, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf200,
+       0xf200, 0xf200, 0xf700, 0xf200, 0xfb7a, 0xfb78, 0xf916, 0xfb76,
+       0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
+       0xf703, 0xf200, 0xf207, 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510,
+       0xf511, 0xf512, 0xf513, 0xf514, 0xf515, 0xf208, 0xf202, 0xf911,
+       0xf912, 0xf913, 0xf30b, 0xf90e, 0xf90f, 0xf910, 0xf30a, 0xf90b,
+       0xf90c, 0xf90d, 0xf90a, 0xf310, 0xf206, 0xf200, 0xf07c, 0xf516,
+       0xf517, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short ctrl_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
+       0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
+       0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
+       0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013,
+       0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
+       0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016,
+       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf700, 0xf30c,
+       0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+       0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf204, 0xf307,
+       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf10a,
+       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short shift_ctrl_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200,
+       0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
+       0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013,
+       0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
+       0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016,
+       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
+       0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xf307,
+       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short alt_map[NR_KEYS] = {
+       0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836,
+       0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf87f, 0xf809,
+       0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
+       0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d, 0xf702, 0xf861, 0xf873,
+       0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b,
+       0xf827, 0xf860, 0xf700, 0xf85c, 0xf87a, 0xf878, 0xf863, 0xf876,
+       0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf30c,
+       0xf703, 0xf820, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504,
+       0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf209, 0xf907,
+       0xf908, 0xf909, 0xf30b, 0xf904, 0xf905, 0xf906, 0xf30a, 0xf901,
+       0xf902, 0xf903, 0xf900, 0xf310, 0xf206, 0xf200, 0xf83c, 0xf50a,
+       0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf210, 0xf211, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short ctrl_alt_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809,
+       0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813,
+       0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200,
+       0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816,
+       0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
+       0xf703, 0xf200, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504,
+       0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf200, 0xf307,
+       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+       0xf302, 0xf303, 0xf300, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf50a,
+       0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+       plain_map, shift_map, altgr_map, NULL,
+       ctrl_map, shift_ctrl_map, NULL, NULL,
+       alt_map, NULL, NULL, NULL,
+       ctrl_alt_map, NULL
+};
+
+unsigned int keymap_count = 7;
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+       '\033', '[', '[', 'A', 0, 
+       '\033', '[', '[', 'B', 0, 
+       '\033', '[', '[', 'C', 0, 
+       '\033', '[', '[', 'D', 0, 
+       '\033', '[', '[', 'E', 0, 
+       '\033', '[', '1', '7', '~', 0, 
+       '\033', '[', '1', '8', '~', 0, 
+       '\033', '[', '1', '9', '~', 0, 
+       '\033', '[', '2', '0', '~', 0, 
+       '\033', '[', '2', '1', '~', 0, 
+       '\033', '[', '2', '3', '~', 0, 
+       '\033', '[', '2', '4', '~', 0, 
+       '\033', '[', '2', '5', '~', 0, 
+       '\033', '[', '2', '6', '~', 0, 
+       '\033', '[', '2', '8', '~', 0, 
+       '\033', '[', '2', '9', '~', 0, 
+       '\033', '[', '3', '1', '~', 0, 
+       '\033', '[', '3', '2', '~', 0, 
+       '\033', '[', '3', '3', '~', 0, 
+       '\033', '[', '3', '4', '~', 0, 
+       '\033', '[', '1', '~', 0, 
+       '\033', '[', '2', '~', 0, 
+       '\033', '[', '3', '~', 0, 
+       '\033', '[', '4', '~', 0, 
+       '\033', '[', '5', '~', 0, 
+       '\033', '[', '6', '~', 0, 
+       '\033', '[', 'M', 0, 
+       '\033', '[', 'P', 0, 
+};
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0;          /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+       func_buf + 0,
+       func_buf + 5,
+       func_buf + 10,
+       func_buf + 15,
+       func_buf + 20,
+       func_buf + 25,
+       func_buf + 31,
+       func_buf + 37,
+       func_buf + 43,
+       func_buf + 49,
+       func_buf + 55,
+       func_buf + 61,
+       func_buf + 67,
+       func_buf + 73,
+       func_buf + 79,
+       func_buf + 85,
+       func_buf + 91,
+       func_buf + 97,
+       func_buf + 103,
+       func_buf + 109,
+       func_buf + 115,
+       func_buf + 120,
+       func_buf + 125,
+       func_buf + 130,
+       func_buf + 135,
+       func_buf + 140,
+       func_buf + 145,
+       NULL,
+       NULL,
+       func_buf + 149,
+       NULL,
+};
+
+struct kbdiacruc accent_table[MAX_DIACR] = {
+       {'`', 'A', 0300},       {'`', 'a', 0340},
+       {'\'', 'A', 0301},      {'\'', 'a', 0341},
+       {'^', 'A', 0302},       {'^', 'a', 0342},
+       {'~', 'A', 0303},       {'~', 'a', 0343},
+       {'"', 'A', 0304},       {'"', 'a', 0344},
+       {'O', 'A', 0305},       {'o', 'a', 0345},
+       {'0', 'A', 0305},       {'0', 'a', 0345},
+       {'A', 'A', 0305},       {'a', 'a', 0345},
+       {'A', 'E', 0306},       {'a', 'e', 0346},
+       {',', 'C', 0307},       {',', 'c', 0347},
+       {'`', 'E', 0310},       {'`', 'e', 0350},
+       {'\'', 'E', 0311},      {'\'', 'e', 0351},
+       {'^', 'E', 0312},       {'^', 'e', 0352},
+       {'"', 'E', 0313},       {'"', 'e', 0353},
+       {'`', 'I', 0314},       {'`', 'i', 0354},
+       {'\'', 'I', 0315},      {'\'', 'i', 0355},
+       {'^', 'I', 0316},       {'^', 'i', 0356},
+       {'"', 'I', 0317},       {'"', 'i', 0357},
+       {'-', 'D', 0320},       {'-', 'd', 0360},
+       {'~', 'N', 0321},       {'~', 'n', 0361},
+       {'`', 'O', 0322},       {'`', 'o', 0362},
+       {'\'', 'O', 0323},      {'\'', 'o', 0363},
+       {'^', 'O', 0324},       {'^', 'o', 0364},
+       {'~', 'O', 0325},       {'~', 'o', 0365},
+       {'"', 'O', 0326},       {'"', 'o', 0366},
+       {'/', 'O', 0330},       {'/', 'o', 0370},
+       {'`', 'U', 0331},       {'`', 'u', 0371},
+       {'\'', 'U', 0332},      {'\'', 'u', 0372},
+       {'^', 'U', 0333},       {'^', 'u', 0373},
+       {'"', 'U', 0334},       {'"', 'u', 0374},
+       {'\'', 'Y', 0335},      {'\'', 'y', 0375},
+       {'T', 'H', 0336},       {'t', 'h', 0376},
+       {'s', 's', 0337},       {'"', 'y', 0377},
+       {'s', 'z', 0337},       {'i', 'j', 0377},
+};
+
+unsigned int accent_table_size = 68;
diff --git a/drivers/tty/vt/defkeymap.map b/drivers/tty/vt/defkeymap.map
new file mode 100644 (file)
index 0000000..50b30ca
--- /dev/null
@@ -0,0 +1,357 @@
+# Default kernel keymap. This uses 7 modifier combinations.
+keymaps 0-2,4-5,8,12
+# Change the above line into
+#      keymaps 0-2,4-6,8,12
+# in case you want the entries
+#      altgr   control keycode  83 = Boot            
+#      altgr   control keycode 111 = Boot            
+# below.
+#
+# In fact AltGr is used very little, and one more keymap can
+# be saved by mapping AltGr to Alt (and adapting a few entries):
+# keycode 100 = Alt
+#
+keycode   1 = Escape           Escape          
+       alt     keycode   1 = Meta_Escape     
+keycode   2 = one              exclam          
+       alt     keycode   2 = Meta_one        
+keycode   3 = two              at               at              
+       control keycode   3 = nul             
+       shift   control keycode   3 = nul             
+       alt     keycode   3 = Meta_two        
+keycode   4 = three            numbersign      
+       control keycode   4 = Escape          
+       alt     keycode   4 = Meta_three      
+keycode   5 = four             dollar           dollar          
+       control keycode   5 = Control_backslash
+       alt     keycode   5 = Meta_four       
+keycode   6 = five             percent         
+       control keycode   6 = Control_bracketright
+       alt     keycode   6 = Meta_five       
+keycode   7 = six              asciicircum     
+       control keycode   7 = Control_asciicircum
+       alt     keycode   7 = Meta_six        
+keycode   8 = seven            ampersand        braceleft       
+       control keycode   8 = Control_underscore
+       alt     keycode   8 = Meta_seven      
+keycode   9 = eight            asterisk         bracketleft     
+       control keycode   9 = Delete          
+       alt     keycode   9 = Meta_eight      
+keycode  10 = nine             parenleft        bracketright    
+       alt     keycode  10 = Meta_nine       
+keycode  11 = zero             parenright       braceright      
+       alt     keycode  11 = Meta_zero       
+keycode  12 = minus            underscore       backslash       
+       control keycode  12 = Control_underscore
+       shift   control keycode  12 = Control_underscore
+       alt     keycode  12 = Meta_minus      
+keycode  13 = equal            plus            
+       alt     keycode  13 = Meta_equal      
+keycode  14 = Delete           Delete          
+       control keycode  14 = BackSpace
+       alt     keycode  14 = Meta_Delete     
+keycode  15 = Tab              Tab             
+       alt     keycode  15 = Meta_Tab        
+keycode  16 = q               
+keycode  17 = w               
+keycode  18 = e
+       altgr   keycode  18 = Hex_E   
+keycode  19 = r               
+keycode  20 = t               
+keycode  21 = y               
+keycode  22 = u               
+keycode  23 = i               
+keycode  24 = o               
+keycode  25 = p               
+keycode  26 = bracketleft      braceleft       
+       control keycode  26 = Escape          
+       alt     keycode  26 = Meta_bracketleft
+keycode  27 = bracketright     braceright       asciitilde      
+       control keycode  27 = Control_bracketright
+       alt     keycode  27 = Meta_bracketright
+keycode  28 = Return          
+       alt     keycode  28 = Meta_Control_m  
+keycode  29 = Control         
+keycode  30 = a
+       altgr   keycode  30 = Hex_A
+keycode  31 = s               
+keycode  32 = d
+       altgr   keycode  32 = Hex_D   
+keycode  33 = f
+       altgr   keycode  33 = Hex_F               
+keycode  34 = g               
+keycode  35 = h               
+keycode  36 = j               
+keycode  37 = k               
+keycode  38 = l               
+keycode  39 = semicolon        colon           
+       alt     keycode  39 = Meta_semicolon  
+keycode  40 = apostrophe       quotedbl        
+       control keycode  40 = Control_g       
+       alt     keycode  40 = Meta_apostrophe 
+keycode  41 = grave            asciitilde      
+       control keycode  41 = nul             
+       alt     keycode  41 = Meta_grave      
+keycode  42 = Shift           
+keycode  43 = backslash        bar             
+       control keycode  43 = Control_backslash
+       alt     keycode  43 = Meta_backslash  
+keycode  44 = z               
+keycode  45 = x               
+keycode  46 = c
+       altgr   keycode  46 = Hex_C   
+keycode  47 = v               
+keycode  48 = b
+       altgr   keycode  48 = Hex_B
+keycode  49 = n               
+keycode  50 = m               
+keycode  51 = comma            less            
+       alt     keycode  51 = Meta_comma      
+keycode  52 = period           greater         
+       control keycode  52 = Compose         
+       alt     keycode  52 = Meta_period     
+keycode  53 = slash            question        
+       control keycode  53 = Delete          
+       alt     keycode  53 = Meta_slash      
+keycode  54 = Shift           
+keycode  55 = KP_Multiply     
+keycode  56 = Alt             
+keycode  57 = space            space           
+       control keycode  57 = nul             
+       alt     keycode  57 = Meta_space      
+keycode  58 = Caps_Lock       
+keycode  59 = F1               F11              Console_13      
+       control keycode  59 = F1              
+       alt     keycode  59 = Console_1       
+       control alt     keycode  59 = Console_1       
+keycode  60 = F2               F12              Console_14      
+       control keycode  60 = F2              
+       alt     keycode  60 = Console_2       
+       control alt     keycode  60 = Console_2       
+keycode  61 = F3               F13              Console_15      
+       control keycode  61 = F3              
+       alt     keycode  61 = Console_3       
+       control alt     keycode  61 = Console_3       
+keycode  62 = F4               F14              Console_16      
+       control keycode  62 = F4              
+       alt     keycode  62 = Console_4       
+       control alt     keycode  62 = Console_4       
+keycode  63 = F5               F15              Console_17      
+       control keycode  63 = F5              
+       alt     keycode  63 = Console_5       
+       control alt     keycode  63 = Console_5       
+keycode  64 = F6               F16              Console_18      
+       control keycode  64 = F6              
+       alt     keycode  64 = Console_6       
+       control alt     keycode  64 = Console_6       
+keycode  65 = F7               F17              Console_19      
+       control keycode  65 = F7              
+       alt     keycode  65 = Console_7       
+       control alt     keycode  65 = Console_7       
+keycode  66 = F8               F18              Console_20      
+       control keycode  66 = F8              
+       alt     keycode  66 = Console_8       
+       control alt     keycode  66 = Console_8       
+keycode  67 = F9               F19              Console_21      
+       control keycode  67 = F9              
+       alt     keycode  67 = Console_9       
+       control alt     keycode  67 = Console_9       
+keycode  68 = F10              F20              Console_22      
+       control keycode  68 = F10             
+       alt     keycode  68 = Console_10      
+       control alt     keycode  68 = Console_10      
+keycode  69 = Num_Lock
+       shift   keycode  69 = Bare_Num_Lock
+keycode  70 = Scroll_Lock      Show_Memory      Show_Registers  
+       control keycode  70 = Show_State      
+       alt     keycode  70 = Scroll_Lock     
+keycode  71 = KP_7            
+       alt     keycode  71 = Ascii_7         
+       altgr   keycode  71 = Hex_7         
+keycode  72 = KP_8            
+       alt     keycode  72 = Ascii_8         
+       altgr   keycode  72 = Hex_8         
+keycode  73 = KP_9            
+       alt     keycode  73 = Ascii_9         
+       altgr   keycode  73 = Hex_9         
+keycode  74 = KP_Subtract     
+keycode  75 = KP_4            
+       alt     keycode  75 = Ascii_4         
+       altgr   keycode  75 = Hex_4         
+keycode  76 = KP_5            
+       alt     keycode  76 = Ascii_5         
+       altgr   keycode  76 = Hex_5         
+keycode  77 = KP_6            
+       alt     keycode  77 = Ascii_6         
+       altgr   keycode  77 = Hex_6         
+keycode  78 = KP_Add          
+keycode  79 = KP_1            
+       alt     keycode  79 = Ascii_1         
+       altgr   keycode  79 = Hex_1         
+keycode  80 = KP_2            
+       alt     keycode  80 = Ascii_2         
+       altgr   keycode  80 = Hex_2         
+keycode  81 = KP_3            
+       alt     keycode  81 = Ascii_3         
+       altgr   keycode  81 = Hex_3         
+keycode  82 = KP_0            
+       alt     keycode  82 = Ascii_0         
+       altgr   keycode  82 = Hex_0         
+keycode  83 = KP_Period       
+#      altgr   control keycode  83 = Boot            
+       control alt     keycode  83 = Boot            
+keycode  84 = Last_Console    
+keycode  85 =
+keycode  86 = less             greater          bar             
+       alt     keycode  86 = Meta_less       
+keycode  87 = F11              F11              Console_23      
+       control keycode  87 = F11             
+       alt     keycode  87 = Console_11      
+       control alt     keycode  87 = Console_11      
+keycode  88 = F12              F12              Console_24      
+       control keycode  88 = F12             
+       alt     keycode  88 = Console_12      
+       control alt     keycode  88 = Console_12      
+keycode  89 =
+keycode  90 =
+keycode  91 =
+keycode  92 =
+keycode  93 =
+keycode  94 =
+keycode  95 =
+keycode  96 = KP_Enter        
+keycode  97 = Control         
+keycode  98 = KP_Divide       
+keycode  99 = Control_backslash
+       control keycode  99 = Control_backslash
+       alt     keycode  99 = Control_backslash
+keycode 100 = AltGr           
+keycode 101 = Break           
+keycode 102 = Find            
+keycode 103 = Up              
+keycode 104 = Prior           
+       shift   keycode 104 = Scroll_Backward 
+keycode 105 = Left            
+       alt     keycode 105 = Decr_Console
+keycode 106 = Right           
+       alt     keycode 106 = Incr_Console
+keycode 107 = Select          
+keycode 108 = Down            
+keycode 109 = Next            
+       shift   keycode 109 = Scroll_Forward  
+keycode 110 = Insert          
+keycode 111 = Remove          
+#      altgr   control keycode 111 = Boot            
+       control alt     keycode 111 = Boot            
+keycode 112 = Macro           
+keycode 113 = F13             
+keycode 114 = F14             
+keycode 115 = Help            
+keycode 116 = Do              
+keycode 117 = F17             
+keycode 118 = KP_MinPlus      
+keycode 119 = Pause           
+keycode 120 =
+keycode 121 =
+keycode 122 =
+keycode 123 =
+keycode 124 =
+keycode 125 =
+keycode 126 =
+keycode 127 =
+string F1 = "\033[[A"
+string F2 = "\033[[B"
+string F3 = "\033[[C"
+string F4 = "\033[[D"
+string F5 = "\033[[E"
+string F6 = "\033[17~"
+string F7 = "\033[18~"
+string F8 = "\033[19~"
+string F9 = "\033[20~"
+string F10 = "\033[21~"
+string F11 = "\033[23~"
+string F12 = "\033[24~"
+string F13 = "\033[25~"
+string F14 = "\033[26~"
+string F15 = "\033[28~"
+string F16 = "\033[29~"
+string F17 = "\033[31~"
+string F18 = "\033[32~"
+string F19 = "\033[33~"
+string F20 = "\033[34~"
+string Find = "\033[1~"
+string Insert = "\033[2~"
+string Remove = "\033[3~"
+string Select = "\033[4~"
+string Prior = "\033[5~"
+string Next = "\033[6~"
+string Macro = "\033[M"
+string Pause = "\033[P"
+compose '`' 'A' to 'À'
+compose '`' 'a' to 'à'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ã'
+compose '~' 'a' to 'ã'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Å'
+compose 'o' 'a' to 'å'
+compose '0' 'A' to 'Å'
+compose '0' 'a' to 'å'
+compose 'A' 'A' to 'Å'
+compose 'a' 'a' to 'å'
+compose 'A' 'E' to 'Æ'
+compose 'a' 'e' to 'æ'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'È'
+compose '`' 'e' to 'è'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ê'
+compose '^' 'e' to 'ê'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ì'
+compose '`' 'i' to 'ì'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ï'
+compose '"' 'i' to 'ï'
+compose '-' 'D' to 'Ð'
+compose '-' 'd' to 'ð'
+compose '~' 'N' to 'Ñ'
+compose '~' 'n' to 'ñ'
+compose '`' 'O' to 'Ò'
+compose '`' 'o' to 'ò'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Õ'
+compose '~' 'o' to 'õ'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ø'
+compose '/' 'o' to 'ø'
+compose '`' 'U' to 'Ù'
+compose '`' 'u' to 'ù'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Û'
+compose '^' 'u' to 'û'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Þ'
+compose 't' 'h' to 'þ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to 'ÿ'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to 'ÿ'
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
new file mode 100644 (file)
index 0000000..e95d787
--- /dev/null
@@ -0,0 +1,1454 @@
+/*
+ * linux/drivers/char/keyboard.c
+ *
+ * Written for linux by Johan Myreen as a translation from
+ * the assembly version by Linus (with diacriticals added)
+ *
+ * Some additional features added by Christoph Niemann (ChN), March 1993
+ *
+ * Loadable keymaps by Risto Kankkunen, May 1993
+ *
+ * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
+ * Added decr/incr_console, dynamic keymaps, Unicode support,
+ * dynamic function/string keys, led setting,  Sept 1994
+ * `Sticky' modifier keys, 951006.
+ *
+ * 11-11-96: SAK should now work in the raw mode (Martin Mares)
+ *
+ * Modified to provide 'generic' keyboard support by Hamish Macdonald
+ * Merge with the m68k keyboard driver and split-off of the PC low-level
+ * parts by Geert Uytterhoeven, May 1997
+ *
+ * 27-05-97: Added support for the Magic SysRq Key (Martin Mares)
+ * 30-07-98: Dead keys redone, aeb@cwi.nl.
+ * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik)
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/consolemap.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/kbd_diacr.h>
+#include <linux/vt_kern.h>
+#include <linux/input.h>
+#include <linux/reboot.h>
+#include <linux/notifier.h>
+#include <linux/jiffies.h>
+
+extern void ctrl_alt_del(void);
+
+/*
+ * Exported functions/variables
+ */
+
+#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
+
+/*
+ * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
+ * This seems a good reason to start with NumLock off. On HIL keyboards
+ * of PARISC machines however there is no NumLock key and everyone expects the keypad
+ * to be used for numbers.
+ */
+
+#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
+#define KBD_DEFLEDS (1 << VC_NUMLOCK)
+#else
+#define KBD_DEFLEDS 0
+#endif
+
+#define KBD_DEFLOCK 0
+
+void compute_shiftstate(void);
+
+/*
+ * Handler Tables.
+ */
+
+#define K_HANDLERS\
+       k_self,         k_fn,           k_spec,         k_pad,\
+       k_dead,         k_cons,         k_cur,          k_shift,\
+       k_meta,         k_ascii,        k_lock,         k_lowercase,\
+       k_slock,        k_dead2,        k_brl,          k_ignore
+
+typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value,
+                           char up_flag);
+static k_handler_fn K_HANDLERS;
+static k_handler_fn *k_handler[16] = { K_HANDLERS };
+
+#define FN_HANDLERS\
+       fn_null,        fn_enter,       fn_show_ptregs, fn_show_mem,\
+       fn_show_state,  fn_send_intr,   fn_lastcons,    fn_caps_toggle,\
+       fn_num,         fn_hold,        fn_scroll_forw, fn_scroll_back,\
+       fn_boot_it,     fn_caps_on,     fn_compose,     fn_SAK,\
+       fn_dec_console, fn_inc_console, fn_spawn_con,   fn_bare_num
+
+typedef void (fn_handler_fn)(struct vc_data *vc);
+static fn_handler_fn FN_HANDLERS;
+static fn_handler_fn *fn_handler[] = { FN_HANDLERS };
+
+/*
+ * Variables exported for vt_ioctl.c
+ */
+
+/* maximum values each key_handler can handle */
+const int max_vals[] = {
+       255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
+       NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
+       255, NR_LOCK - 1, 255, NR_BRL - 1
+};
+
+const int NR_TYPES = ARRAY_SIZE(max_vals);
+
+struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+EXPORT_SYMBOL_GPL(kbd_table);
+static struct kbd_struct *kbd = kbd_table;
+
+struct vt_spawn_console vt_spawn_con = {
+       .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock),
+       .pid  = NULL,
+       .sig  = 0,
+};
+
+/*
+ * Variables exported for vt.c
+ */
+
+int shift_state = 0;
+
+/*
+ * Internal Data.
+ */
+
+static struct input_handler kbd_handler;
+static DEFINE_SPINLOCK(kbd_event_lock);
+static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
+static unsigned char shift_down[NR_SHIFT];             /* shift state counters.. */
+static bool dead_key_next;
+static int npadch = -1;                                        /* -1 or number assembled on pad */
+static unsigned int diacr;
+static char rep;                                       /* flag telling character repeat */
+
+static unsigned char ledstate = 0xff;                  /* undefined */
+static unsigned char ledioctl;
+
+static struct ledptr {
+       unsigned int *addr;
+       unsigned int mask;
+       unsigned char valid:1;
+} ledptrs[3];
+
+/*
+ * Notifier list for console keyboard events
+ */
+static ATOMIC_NOTIFIER_HEAD(keyboard_notifier_list);
+
+int register_keyboard_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_register(&keyboard_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(register_keyboard_notifier);
+
+int unregister_keyboard_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_unregister(&keyboard_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_keyboard_notifier);
+
+/*
+ * Translation of scancodes to keycodes. We set them on only the first
+ * keyboard in the list that accepts the scancode and keycode.
+ * Explanation for not choosing the first attached keyboard anymore:
+ *  USB keyboards for example have two event devices: one for all "normal"
+ *  keys and one for extra function keys (like "volume up", "make coffee",
+ *  etc.). So this means that scancodes for the extra function keys won't
+ *  be valid for the first event device, but will be for the second.
+ */
+
+struct getset_keycode_data {
+       struct input_keymap_entry ke;
+       int error;
+};
+
+static int getkeycode_helper(struct input_handle *handle, void *data)
+{
+       struct getset_keycode_data *d = data;
+
+       d->error = input_get_keycode(handle->dev, &d->ke);
+
+       return d->error == 0; /* stop as soon as we successfully get one */
+}
+
+int getkeycode(unsigned int scancode)
+{
+       struct getset_keycode_data d = {
+               .ke     = {
+                       .flags          = 0,
+                       .len            = sizeof(scancode),
+                       .keycode        = 0,
+               },
+               .error  = -ENODEV,
+       };
+
+       memcpy(d.ke.scancode, &scancode, sizeof(scancode));
+
+       input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper);
+
+       return d.error ?: d.ke.keycode;
+}
+
+static int setkeycode_helper(struct input_handle *handle, void *data)
+{
+       struct getset_keycode_data *d = data;
+
+       d->error = input_set_keycode(handle->dev, &d->ke);
+
+       return d->error == 0; /* stop as soon as we successfully set one */
+}
+
+int setkeycode(unsigned int scancode, unsigned int keycode)
+{
+       struct getset_keycode_data d = {
+               .ke     = {
+                       .flags          = 0,
+                       .len            = sizeof(scancode),
+                       .keycode        = keycode,
+               },
+               .error  = -ENODEV,
+       };
+
+       memcpy(d.ke.scancode, &scancode, sizeof(scancode));
+
+       input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper);
+
+       return d.error;
+}
+
+/*
+ * Making beeps and bells. Note that we prefer beeps to bells, but when
+ * shutting the sound off we do both.
+ */
+
+static int kd_sound_helper(struct input_handle *handle, void *data)
+{
+       unsigned int *hz = data;
+       struct input_dev *dev = handle->dev;
+
+       if (test_bit(EV_SND, dev->evbit)) {
+               if (test_bit(SND_TONE, dev->sndbit)) {
+                       input_inject_event(handle, EV_SND, SND_TONE, *hz);
+                       if (*hz)
+                               return 0;
+               }
+               if (test_bit(SND_BELL, dev->sndbit))
+                       input_inject_event(handle, EV_SND, SND_BELL, *hz ? 1 : 0);
+       }
+
+       return 0;
+}
+
+static void kd_nosound(unsigned long ignored)
+{
+       static unsigned int zero;
+
+       input_handler_for_each_handle(&kbd_handler, &zero, kd_sound_helper);
+}
+
+static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0);
+
+void kd_mksound(unsigned int hz, unsigned int ticks)
+{
+       del_timer_sync(&kd_mksound_timer);
+
+       input_handler_for_each_handle(&kbd_handler, &hz, kd_sound_helper);
+
+       if (hz && ticks)
+               mod_timer(&kd_mksound_timer, jiffies + ticks);
+}
+EXPORT_SYMBOL(kd_mksound);
+
+/*
+ * Setting the keyboard rate.
+ */
+
+static int kbd_rate_helper(struct input_handle *handle, void *data)
+{
+       struct input_dev *dev = handle->dev;
+       struct kbd_repeat *rep = data;
+
+       if (test_bit(EV_REP, dev->evbit)) {
+
+               if (rep[0].delay > 0)
+                       input_inject_event(handle,
+                                          EV_REP, REP_DELAY, rep[0].delay);
+               if (rep[0].period > 0)
+                       input_inject_event(handle,
+                                          EV_REP, REP_PERIOD, rep[0].period);
+
+               rep[1].delay = dev->rep[REP_DELAY];
+               rep[1].period = dev->rep[REP_PERIOD];
+       }
+
+       return 0;
+}
+
+int kbd_rate(struct kbd_repeat *rep)
+{
+       struct kbd_repeat data[2] = { *rep };
+
+       input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper);
+       *rep = data[1]; /* Copy currently used settings */
+
+       return 0;
+}
+
+/*
+ * Helper Functions.
+ */
+static void put_queue(struct vc_data *vc, int ch)
+{
+       struct tty_struct *tty = vc->port.tty;
+
+       if (tty) {
+               tty_insert_flip_char(tty, ch, 0);
+               con_schedule_flip(tty);
+       }
+}
+
+static void puts_queue(struct vc_data *vc, char *cp)
+{
+       struct tty_struct *tty = vc->port.tty;
+
+       if (!tty)
+               return;
+
+       while (*cp) {
+               tty_insert_flip_char(tty, *cp, 0);
+               cp++;
+       }
+       con_schedule_flip(tty);
+}
+
+static void applkey(struct vc_data *vc, int key, char mode)
+{
+       static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
+
+       buf[1] = (mode ? 'O' : '[');
+       buf[2] = key;
+       puts_queue(vc, buf);
+}
+
+/*
+ * Many other routines do put_queue, but I think either
+ * they produce ASCII, or they produce some user-assigned
+ * string, and in both cases we might assume that it is
+ * in utf-8 already.
+ */
+static void to_utf8(struct vc_data *vc, uint c)
+{
+       if (c < 0x80)
+               /*  0******* */
+               put_queue(vc, c);
+       else if (c < 0x800) {
+               /* 110***** 10****** */
+               put_queue(vc, 0xc0 | (c >> 6));
+               put_queue(vc, 0x80 | (c & 0x3f));
+       } else if (c < 0x10000) {
+               if (c >= 0xD800 && c < 0xE000)
+                       return;
+               if (c == 0xFFFF)
+                       return;
+               /* 1110**** 10****** 10****** */
+               put_queue(vc, 0xe0 | (c >> 12));
+               put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
+               put_queue(vc, 0x80 | (c & 0x3f));
+       } else if (c < 0x110000) {
+               /* 11110*** 10****** 10****** 10****** */
+               put_queue(vc, 0xf0 | (c >> 18));
+               put_queue(vc, 0x80 | ((c >> 12) & 0x3f));
+               put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
+               put_queue(vc, 0x80 | (c & 0x3f));
+       }
+}
+
+/*
+ * Called after returning from RAW mode or when changing consoles - recompute
+ * shift_down[] and shift_state from key_down[] maybe called when keymap is
+ * undefined, so that shiftkey release is seen
+ */
+void compute_shiftstate(void)
+{
+       unsigned int i, j, k, sym, val;
+
+       shift_state = 0;
+       memset(shift_down, 0, sizeof(shift_down));
+
+       for (i = 0; i < ARRAY_SIZE(key_down); i++) {
+
+               if (!key_down[i])
+                       continue;
+
+               k = i * BITS_PER_LONG;
+
+               for (j = 0; j < BITS_PER_LONG; j++, k++) {
+
+                       if (!test_bit(k, key_down))
+                               continue;
+
+                       sym = U(key_maps[0][k]);
+                       if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
+                               continue;
+
+                       val = KVAL(sym);
+                       if (val == KVAL(K_CAPSSHIFT))
+                               val = KVAL(K_SHIFT);
+
+                       shift_down[val]++;
+                       shift_state |= (1 << val);
+               }
+       }
+}
+
+/*
+ * We have a combining character DIACR here, followed by the character CH.
+ * If the combination occurs in the table, return the corresponding value.
+ * Otherwise, if CH is a space or equals DIACR, return DIACR.
+ * Otherwise, conclude that DIACR was not combining after all,
+ * queue it and return CH.
+ */
+static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch)
+{
+       unsigned int d = diacr;
+       unsigned int i;
+
+       diacr = 0;
+
+       if ((d & ~0xff) == BRL_UC_ROW) {
+               if ((ch & ~0xff) == BRL_UC_ROW)
+                       return d | ch;
+       } else {
+               for (i = 0; i < accent_table_size; i++)
+                       if (accent_table[i].diacr == d && accent_table[i].base == ch)
+                               return accent_table[i].result;
+       }
+
+       if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d)
+               return d;
+
+       if (kbd->kbdmode == VC_UNICODE)
+               to_utf8(vc, d);
+       else {
+               int c = conv_uni_to_8bit(d);
+               if (c != -1)
+                       put_queue(vc, c);
+       }
+
+       return ch;
+}
+
+/*
+ * Special function handlers
+ */
+static void fn_enter(struct vc_data *vc)
+{
+       if (diacr) {
+               if (kbd->kbdmode == VC_UNICODE)
+                       to_utf8(vc, diacr);
+               else {
+                       int c = conv_uni_to_8bit(diacr);
+                       if (c != -1)
+                               put_queue(vc, c);
+               }
+               diacr = 0;
+       }
+
+       put_queue(vc, 13);
+       if (vc_kbd_mode(kbd, VC_CRLF))
+               put_queue(vc, 10);
+}
+
+static void fn_caps_toggle(struct vc_data *vc)
+{
+       if (rep)
+               return;
+
+       chg_vc_kbd_led(kbd, VC_CAPSLOCK);
+}
+
+static void fn_caps_on(struct vc_data *vc)
+{
+       if (rep)
+               return;
+
+       set_vc_kbd_led(kbd, VC_CAPSLOCK);
+}
+
+static void fn_show_ptregs(struct vc_data *vc)
+{
+       struct pt_regs *regs = get_irq_regs();
+
+       if (regs)
+               show_regs(regs);
+}
+
+static void fn_hold(struct vc_data *vc)
+{
+       struct tty_struct *tty = vc->port.tty;
+
+       if (rep || !tty)
+               return;
+
+       /*
+        * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
+        * these routines are also activated by ^S/^Q.
+        * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
+        */
+       if (tty->stopped)
+               start_tty(tty);
+       else
+               stop_tty(tty);
+}
+
+static void fn_num(struct vc_data *vc)
+{
+       if (vc_kbd_mode(kbd, VC_APPLIC))
+               applkey(vc, 'P', 1);
+       else
+               fn_bare_num(vc);
+}
+
+/*
+ * Bind this to Shift-NumLock if you work in application keypad mode
+ * but want to be able to change the NumLock flag.
+ * Bind this to NumLock if you prefer that the NumLock key always
+ * changes the NumLock flag.
+ */
+static void fn_bare_num(struct vc_data *vc)
+{
+       if (!rep)
+               chg_vc_kbd_led(kbd, VC_NUMLOCK);
+}
+
+static void fn_lastcons(struct vc_data *vc)
+{
+       /* switch to the last used console, ChN */
+       set_console(last_console);
+}
+
+static void fn_dec_console(struct vc_data *vc)
+{
+       int i, cur = fg_console;
+
+       /* Currently switching?  Queue this next switch relative to that. */
+       if (want_console != -1)
+               cur = want_console;
+
+       for (i = cur - 1; i != cur; i--) {
+               if (i == -1)
+                       i = MAX_NR_CONSOLES - 1;
+               if (vc_cons_allocated(i))
+                       break;
+       }
+       set_console(i);
+}
+
+static void fn_inc_console(struct vc_data *vc)
+{
+       int i, cur = fg_console;
+
+       /* Currently switching?  Queue this next switch relative to that. */
+       if (want_console != -1)
+               cur = want_console;
+
+       for (i = cur+1; i != cur; i++) {
+               if (i == MAX_NR_CONSOLES)
+                       i = 0;
+               if (vc_cons_allocated(i))
+                       break;
+       }
+       set_console(i);
+}
+
+static void fn_send_intr(struct vc_data *vc)
+{
+       struct tty_struct *tty = vc->port.tty;
+
+       if (!tty)
+               return;
+       tty_insert_flip_char(tty, 0, TTY_BREAK);
+       con_schedule_flip(tty);
+}
+
+static void fn_scroll_forw(struct vc_data *vc)
+{
+       scrollfront(vc, 0);
+}
+
+static void fn_scroll_back(struct vc_data *vc)
+{
+       scrollback(vc, 0);
+}
+
+static void fn_show_mem(struct vc_data *vc)
+{
+       show_mem();
+}
+
+static void fn_show_state(struct vc_data *vc)
+{
+       show_state();
+}
+
+static void fn_boot_it(struct vc_data *vc)
+{
+       ctrl_alt_del();
+}
+
+static void fn_compose(struct vc_data *vc)
+{
+       dead_key_next = true;
+}
+
+static void fn_spawn_con(struct vc_data *vc)
+{
+       spin_lock(&vt_spawn_con.lock);
+       if (vt_spawn_con.pid)
+               if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) {
+                       put_pid(vt_spawn_con.pid);
+                       vt_spawn_con.pid = NULL;
+               }
+       spin_unlock(&vt_spawn_con.lock);
+}
+
+static void fn_SAK(struct vc_data *vc)
+{
+       struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
+       schedule_work(SAK_work);
+}
+
+static void fn_null(struct vc_data *vc)
+{
+       compute_shiftstate();
+}
+
+/*
+ * Special key handlers
+ */
+static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag)
+{
+}
+
+static void k_spec(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+       if (value >= ARRAY_SIZE(fn_handler))
+               return;
+       if ((kbd->kbdmode == VC_RAW ||
+            kbd->kbdmode == VC_MEDIUMRAW) &&
+            value != KVAL(K_SAK))
+               return;         /* SAK is allowed even in raw mode */
+       fn_handler[value](vc);
+}
+
+static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       pr_err("k_lowercase was called - impossible\n");
+}
+
+static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag)
+{
+       if (up_flag)
+               return;         /* no action, if this is a key release */
+
+       if (diacr)
+               value = handle_diacr(vc, value);
+
+       if (dead_key_next) {
+               dead_key_next = false;
+               diacr = value;
+               return;
+       }
+       if (kbd->kbdmode == VC_UNICODE)
+               to_utf8(vc, value);
+       else {
+               int c = conv_uni_to_8bit(value);
+               if (c != -1)
+                       put_queue(vc, c);
+       }
+}
+
+/*
+ * Handle dead key. Note that we now may have several
+ * dead keys modifying the same character. Very useful
+ * for Vietnamese.
+ */
+static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag)
+{
+       if (up_flag)
+               return;
+
+       diacr = (diacr ? handle_diacr(vc, value) : value);
+}
+
+static void k_self(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       k_unicode(vc, conv_8bit_to_uni(value), up_flag);
+}
+
+static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       k_deadunicode(vc, value, up_flag);
+}
+
+/*
+ * Obsolete - for backwards compatibility only
+ */
+static void k_dead(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
+
+       k_deadunicode(vc, ret_diacr[value], up_flag);
+}
+
+static void k_cons(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+
+       set_console(value);
+}
+
+static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+
+       if ((unsigned)value < ARRAY_SIZE(func_table)) {
+               if (func_table[value])
+                       puts_queue(vc, func_table[value]);
+       } else
+               pr_err("k_fn called with value=%d\n", value);
+}
+
+static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       static const char cur_chars[] = "BDCA";
+
+       if (up_flag)
+               return;
+
+       applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
+}
+
+static void k_pad(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       static const char pad_chars[] = "0123456789+-*/\015,.?()#";
+       static const char app_map[] = "pqrstuvwxylSRQMnnmPQS";
+
+       if (up_flag)
+               return;         /* no action, if this is a key release */
+
+       /* kludge... shift forces cursor/number keys */
+       if (vc_kbd_mode(kbd, VC_APPLIC) && !shift_down[KG_SHIFT]) {
+               applkey(vc, app_map[value], 1);
+               return;
+       }
+
+       if (!vc_kbd_led(kbd, VC_NUMLOCK)) {
+
+               switch (value) {
+               case KVAL(K_PCOMMA):
+               case KVAL(K_PDOT):
+                       k_fn(vc, KVAL(K_REMOVE), 0);
+                       return;
+               case KVAL(K_P0):
+                       k_fn(vc, KVAL(K_INSERT), 0);
+                       return;
+               case KVAL(K_P1):
+                       k_fn(vc, KVAL(K_SELECT), 0);
+                       return;
+               case KVAL(K_P2):
+                       k_cur(vc, KVAL(K_DOWN), 0);
+                       return;
+               case KVAL(K_P3):
+                       k_fn(vc, KVAL(K_PGDN), 0);
+                       return;
+               case KVAL(K_P4):
+                       k_cur(vc, KVAL(K_LEFT), 0);
+                       return;
+               case KVAL(K_P6):
+                       k_cur(vc, KVAL(K_RIGHT), 0);
+                       return;
+               case KVAL(K_P7):
+                       k_fn(vc, KVAL(K_FIND), 0);
+                       return;
+               case KVAL(K_P8):
+                       k_cur(vc, KVAL(K_UP), 0);
+                       return;
+               case KVAL(K_P9):
+                       k_fn(vc, KVAL(K_PGUP), 0);
+                       return;
+               case KVAL(K_P5):
+                       applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC));
+                       return;
+               }
+       }
+
+       put_queue(vc, pad_chars[value]);
+       if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
+               put_queue(vc, 10);
+}
+
+static void k_shift(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       int old_state = shift_state;
+
+       if (rep)
+               return;
+       /*
+        * Mimic typewriter:
+        * a CapsShift key acts like Shift but undoes CapsLock
+        */
+       if (value == KVAL(K_CAPSSHIFT)) {
+               value = KVAL(K_SHIFT);
+               if (!up_flag)
+                       clr_vc_kbd_led(kbd, VC_CAPSLOCK);
+       }
+
+       if (up_flag) {
+               /*
+                * handle the case that two shift or control
+                * keys are depressed simultaneously
+                */
+               if (shift_down[value])
+                       shift_down[value]--;
+       } else
+               shift_down[value]++;
+
+       if (shift_down[value])
+               shift_state |= (1 << value);
+       else
+               shift_state &= ~(1 << value);
+
+       /* kludge */
+       if (up_flag && shift_state != old_state && npadch != -1) {
+               if (kbd->kbdmode == VC_UNICODE)
+                       to_utf8(vc, npadch);
+               else
+                       put_queue(vc, npadch & 0xff);
+               npadch = -1;
+       }
+}
+
+static void k_meta(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+
+       if (vc_kbd_mode(kbd, VC_META)) {
+               put_queue(vc, '\033');
+               put_queue(vc, value);
+       } else
+               put_queue(vc, value | 0x80);
+}
+
+static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       int base;
+
+       if (up_flag)
+               return;
+
+       if (value < 10) {
+               /* decimal input of code, while Alt depressed */
+               base = 10;
+       } else {
+               /* hexadecimal input of code, while AltGr depressed */
+               value -= 10;
+               base = 16;
+       }
+
+       if (npadch == -1)
+               npadch = value;
+       else
+               npadch = npadch * base + value;
+}
+
+static void k_lock(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       if (up_flag || rep)
+               return;
+
+       chg_vc_kbd_lock(kbd, value);
+}
+
+static void k_slock(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       k_shift(vc, value, up_flag);
+       if (up_flag || rep)
+               return;
+
+       chg_vc_kbd_slock(kbd, value);
+       /* try to make Alt, oops, AltGr and such work */
+       if (!key_maps[kbd->lockstate ^ kbd->slockstate]) {
+               kbd->slockstate = 0;
+               chg_vc_kbd_slock(kbd, value);
+       }
+}
+
+/* by default, 300ms interval for combination release */
+static unsigned brl_timeout = 300;
+MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)");
+module_param(brl_timeout, uint, 0644);
+
+static unsigned brl_nbchords = 1;
+MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)");
+module_param(brl_nbchords, uint, 0644);
+
+static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag)
+{
+       static unsigned long chords;
+       static unsigned committed;
+
+       if (!brl_nbchords)
+               k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag);
+       else {
+               committed |= pattern;
+               chords++;
+               if (chords == brl_nbchords) {
+                       k_unicode(vc, BRL_UC_ROW | committed, up_flag);
+                       chords = 0;
+                       committed = 0;
+               }
+       }
+}
+
+static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       static unsigned pressed, committing;
+       static unsigned long releasestart;
+
+       if (kbd->kbdmode != VC_UNICODE) {
+               if (!up_flag)
+                       pr_warning("keyboard mode must be unicode for braille patterns\n");
+               return;
+       }
+
+       if (!value) {
+               k_unicode(vc, BRL_UC_ROW, up_flag);
+               return;
+       }
+
+       if (value > 8)
+               return;
+
+       if (!up_flag) {
+               pressed |= 1 << (value - 1);
+               if (!brl_timeout)
+                       committing = pressed;
+       } else if (brl_timeout) {
+               if (!committing ||
+                   time_after(jiffies,
+                              releasestart + msecs_to_jiffies(brl_timeout))) {
+                       committing = pressed;
+                       releasestart = jiffies;
+               }
+               pressed &= ~(1 << (value - 1));
+               if (!pressed && committing) {
+                       k_brlcommit(vc, committing, 0);
+                       committing = 0;
+               }
+       } else {
+               if (committing) {
+                       k_brlcommit(vc, committing, 0);
+                       committing = 0;
+               }
+               pressed &= ~(1 << (value - 1));
+       }
+}
+
+/*
+ * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
+ * or (ii) whatever pattern of lights people want to show using KDSETLED,
+ * or (iii) specified bits of specified words in kernel memory.
+ */
+unsigned char getledstate(void)
+{
+       return ledstate;
+}
+
+void setledstate(struct kbd_struct *kbd, unsigned int led)
+{
+       if (!(led & ~7)) {
+               ledioctl = led;
+               kbd->ledmode = LED_SHOW_IOCTL;
+       } else
+               kbd->ledmode = LED_SHOW_FLAGS;
+
+       set_leds();
+}
+
+static inline unsigned char getleds(void)
+{
+       struct kbd_struct *kbd = kbd_table + fg_console;
+       unsigned char leds;
+       int i;
+
+       if (kbd->ledmode == LED_SHOW_IOCTL)
+               return ledioctl;
+
+       leds = kbd->ledflagstate;
+
+       if (kbd->ledmode == LED_SHOW_MEM) {
+               for (i = 0; i < 3; i++)
+                       if (ledptrs[i].valid) {
+                               if (*ledptrs[i].addr & ledptrs[i].mask)
+                                       leds |= (1 << i);
+                               else
+                                       leds &= ~(1 << i);
+                       }
+       }
+       return leds;
+}
+
+static int kbd_update_leds_helper(struct input_handle *handle, void *data)
+{
+       unsigned char leds = *(unsigned char *)data;
+
+       if (test_bit(EV_LED, handle->dev->evbit)) {
+               input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
+               input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));
+               input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));
+               input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
+       }
+
+       return 0;
+}
+
+/*
+ * This is the tasklet that updates LED state on all keyboards
+ * attached to the box. The reason we use tasklet is that we
+ * need to handle the scenario when keyboard handler is not
+ * registered yet but we already getting updates form VT to
+ * update led state.
+ */
+static void kbd_bh(unsigned long dummy)
+{
+       unsigned char leds = getleds();
+
+       if (leds != ledstate) {
+               input_handler_for_each_handle(&kbd_handler, &leds,
+                                             kbd_update_leds_helper);
+               ledstate = leds;
+       }
+}
+
+DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
+
+#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
+    defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
+    defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
+    (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ||\
+    defined(CONFIG_AVR32)
+
+#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
+                       ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
+
+static const unsigned short x86_keycodes[256] =
+       { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+        32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+        48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+        64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+        80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92,
+       284,285,309,  0,312, 91,327,328,329,331,333,335,336,337,338,339,
+       367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349,
+       360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355,
+       103,104,105,275,287,279,258,106,274,107,294,364,358,363,362,361,
+       291,108,381,281,290,272,292,305,280, 99,112,257,306,359,113,114,
+       264,117,271,374,379,265,266, 93, 94, 95, 85,259,375,260, 90,116,
+       377,109,111,277,278,282,283,295,296,297,299,300,301,293,303,307,
+       308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330,
+       332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 };
+
+#ifdef CONFIG_SPARC
+static int sparc_l1_a_state;
+extern void sun_do_break(void);
+#endif
+
+static int emulate_raw(struct vc_data *vc, unsigned int keycode,
+                      unsigned char up_flag)
+{
+       int code;
+
+       switch (keycode) {
+
+       case KEY_PAUSE:
+               put_queue(vc, 0xe1);
+               put_queue(vc, 0x1d | up_flag);
+               put_queue(vc, 0x45 | up_flag);
+               break;
+
+       case KEY_HANGEUL:
+               if (!up_flag)
+                       put_queue(vc, 0xf2);
+               break;
+
+       case KEY_HANJA:
+               if (!up_flag)
+                       put_queue(vc, 0xf1);
+               break;
+
+       case KEY_SYSRQ:
+               /*
+                * Real AT keyboards (that's what we're trying
+                * to emulate here emit 0xe0 0x2a 0xe0 0x37 when
+                * pressing PrtSc/SysRq alone, but simply 0x54
+                * when pressing Alt+PrtSc/SysRq.
+                */
+               if (test_bit(KEY_LEFTALT, key_down) ||
+                   test_bit(KEY_RIGHTALT, key_down)) {
+                       put_queue(vc, 0x54 | up_flag);
+               } else {
+                       put_queue(vc, 0xe0);
+                       put_queue(vc, 0x2a | up_flag);
+                       put_queue(vc, 0xe0);
+                       put_queue(vc, 0x37 | up_flag);
+               }
+               break;
+
+       default:
+               if (keycode > 255)
+                       return -1;
+
+               code = x86_keycodes[keycode];
+               if (!code)
+                       return -1;
+
+               if (code & 0x100)
+                       put_queue(vc, 0xe0);
+               put_queue(vc, (code & 0x7f) | up_flag);
+
+               break;
+       }
+
+       return 0;
+}
+
+#else
+
+#define HW_RAW(dev)    0
+
+static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag)
+{
+       if (keycode > 127)
+               return -1;
+
+       put_queue(vc, keycode | up_flag);
+       return 0;
+}
+#endif
+
+static void kbd_rawcode(unsigned char data)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+
+       kbd = kbd_table + vc->vc_num;
+       if (kbd->kbdmode == VC_RAW)
+               put_queue(vc, data);
+}
+
+static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+       unsigned short keysym, *key_map;
+       unsigned char type;
+       bool raw_mode;
+       struct tty_struct *tty;
+       int shift_final;
+       struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
+       int rc;
+
+       tty = vc->port.tty;
+
+       if (tty && (!tty->driver_data)) {
+               /* No driver data? Strange. Okay we fix it then. */
+               tty->driver_data = vc;
+       }
+
+       kbd = kbd_table + vc->vc_num;
+
+#ifdef CONFIG_SPARC
+       if (keycode == KEY_STOP)
+               sparc_l1_a_state = down;
+#endif
+
+       rep = (down == 2);
+
+       raw_mode = (kbd->kbdmode == VC_RAW);
+       if (raw_mode && !hw_raw)
+               if (emulate_raw(vc, keycode, !down << 7))
+                       if (keycode < BTN_MISC && printk_ratelimit())
+                               pr_warning("can't emulate rawmode for keycode %d\n",
+                                          keycode);
+
+#ifdef CONFIG_SPARC
+       if (keycode == KEY_A && sparc_l1_a_state) {
+               sparc_l1_a_state = false;
+               sun_do_break();
+       }
+#endif
+
+       if (kbd->kbdmode == VC_MEDIUMRAW) {
+               /*
+                * This is extended medium raw mode, with keys above 127
+                * encoded as 0, high 7 bits, low 7 bits, with the 0 bearing
+                * the 'up' flag if needed. 0 is reserved, so this shouldn't
+                * interfere with anything else. The two bytes after 0 will
+                * always have the up flag set not to interfere with older
+                * applications. This allows for 16384 different keycodes,
+                * which should be enough.
+                */
+               if (keycode < 128) {
+                       put_queue(vc, keycode | (!down << 7));
+               } else {
+                       put_queue(vc, !down << 7);
+                       put_queue(vc, (keycode >> 7) | 0x80);
+                       put_queue(vc, keycode | 0x80);
+               }
+               raw_mode = true;
+       }
+
+       if (down)
+               set_bit(keycode, key_down);
+       else
+               clear_bit(keycode, key_down);
+
+       if (rep &&
+           (!vc_kbd_mode(kbd, VC_REPEAT) ||
+            (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) {
+               /*
+                * Don't repeat a key if the input buffers are not empty and the
+                * characters get aren't echoed locally. This makes key repeat
+                * usable with slow applications and under heavy loads.
+                */
+               return;
+       }
+
+       param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
+       param.ledstate = kbd->ledflagstate;
+       key_map = key_maps[shift_final];
+
+       rc = atomic_notifier_call_chain(&keyboard_notifier_list,
+                                       KBD_KEYCODE, &param);
+       if (rc == NOTIFY_STOP || !key_map) {
+               atomic_notifier_call_chain(&keyboard_notifier_list,
+                                          KBD_UNBOUND_KEYCODE, &param);
+               compute_shiftstate();
+               kbd->slockstate = 0;
+               return;
+       }
+
+       if (keycode < NR_KEYS)
+               keysym = key_map[keycode];
+       else if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8)
+               keysym = U(K(KT_BRL, keycode - KEY_BRL_DOT1 + 1));
+       else
+               return;
+
+       type = KTYP(keysym);
+
+       if (type < 0xf0) {
+               param.value = keysym;
+               rc = atomic_notifier_call_chain(&keyboard_notifier_list,
+                                               KBD_UNICODE, &param);
+               if (rc != NOTIFY_STOP)
+                       if (down && !raw_mode)
+                               to_utf8(vc, keysym);
+               return;
+       }
+
+       type -= 0xf0;
+
+       if (type == KT_LETTER) {
+               type = KT_LATIN;
+               if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
+                       key_map = key_maps[shift_final ^ (1 << KG_SHIFT)];
+                       if (key_map)
+                               keysym = key_map[keycode];
+               }
+       }
+
+       param.value = keysym;
+       rc = atomic_notifier_call_chain(&keyboard_notifier_list,
+                                       KBD_KEYSYM, &param);
+       if (rc == NOTIFY_STOP)
+               return;
+
+       if (raw_mode && type != KT_SPEC && type != KT_SHIFT)
+               return;
+
+       (*k_handler[type])(vc, keysym & 0xff, !down);
+
+       param.ledstate = kbd->ledflagstate;
+       atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, &param);
+
+       if (type != KT_SLOCK)
+               kbd->slockstate = 0;
+}
+
+static void kbd_event(struct input_handle *handle, unsigned int event_type,
+                     unsigned int event_code, int value)
+{
+       /* We are called with interrupts disabled, just take the lock */
+       spin_lock(&kbd_event_lock);
+
+       if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
+               kbd_rawcode(value);
+       if (event_type == EV_KEY)
+               kbd_keycode(event_code, value, HW_RAW(handle->dev));
+
+       spin_unlock(&kbd_event_lock);
+
+       tasklet_schedule(&keyboard_tasklet);
+       do_poke_blanked_console = 1;
+       schedule_console_callback();
+}
+
+static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
+{
+       int i;
+
+       if (test_bit(EV_SND, dev->evbit))
+               return true;
+
+       if (test_bit(EV_KEY, dev->evbit)) {
+               for (i = KEY_RESERVED; i < BTN_MISC; i++)
+                       if (test_bit(i, dev->keybit))
+                               return true;
+               for (i = KEY_BRL_DOT1; i <= KEY_BRL_DOT10; i++)
+                       if (test_bit(i, dev->keybit))
+                               return true;
+       }
+
+       return false;
+}
+
+/*
+ * When a keyboard (or other input device) is found, the kbd_connect
+ * function is called. The function then looks at the device, and if it
+ * likes it, it can open it and get events from it. In this (kbd_connect)
+ * function, we should decide which VT to bind that keyboard to initially.
+ */
+static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
+                       const struct input_device_id *id)
+{
+       struct input_handle *handle;
+       int error;
+
+       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+       if (!handle)
+               return -ENOMEM;
+
+       handle->dev = dev;
+       handle->handler = handler;
+       handle->name = "kbd";
+
+       error = input_register_handle(handle);
+       if (error)
+               goto err_free_handle;
+
+       error = input_open_device(handle);
+       if (error)
+               goto err_unregister_handle;
+
+       return 0;
+
+ err_unregister_handle:
+       input_unregister_handle(handle);
+ err_free_handle:
+       kfree(handle);
+       return error;
+}
+
+static void kbd_disconnect(struct input_handle *handle)
+{
+       input_close_device(handle);
+       input_unregister_handle(handle);
+       kfree(handle);
+}
+
+/*
+ * Start keyboard handler on the new keyboard by refreshing LED state to
+ * match the rest of the system.
+ */
+static void kbd_start(struct input_handle *handle)
+{
+       tasklet_disable(&keyboard_tasklet);
+
+       if (ledstate != 0xff)
+               kbd_update_leds_helper(handle, &ledstate);
+
+       tasklet_enable(&keyboard_tasklet);
+}
+
+static const struct input_device_id kbd_ids[] = {
+       {
+                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+                .evbit = { BIT_MASK(EV_KEY) },
+        },
+
+       {
+                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+                .evbit = { BIT_MASK(EV_SND) },
+        },
+
+       { },    /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(input, kbd_ids);
+
+static struct input_handler kbd_handler = {
+       .event          = kbd_event,
+       .match          = kbd_match,
+       .connect        = kbd_connect,
+       .disconnect     = kbd_disconnect,
+       .start          = kbd_start,
+       .name           = "kbd",
+       .id_table       = kbd_ids,
+};
+
+int __init kbd_init(void)
+{
+       int i;
+       int error;
+
+        for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               kbd_table[i].ledflagstate = KBD_DEFLEDS;
+               kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
+               kbd_table[i].ledmode = LED_SHOW_FLAGS;
+               kbd_table[i].lockstate = KBD_DEFLOCK;
+               kbd_table[i].slockstate = 0;
+               kbd_table[i].modeflags = KBD_DEFMODE;
+               kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
+       }
+
+       error = input_register_handler(&kbd_handler);
+       if (error)
+               return error;
+
+       tasklet_enable(&keyboard_tasklet);
+       tasklet_schedule(&keyboard_tasklet);
+
+       return 0;
+}
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
new file mode 100644 (file)
index 0000000..ebae344
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * linux/drivers/char/selection.c
+ *
+ * This module exports the functions:
+ *
+ *     'int set_selection(struct tiocl_selection __user *, struct tty_struct *)'
+ *     'void clear_selection(void)'
+ *     'int paste_selection(struct tty_struct *)'
+ *     'int sel_loadlut(char __user *)'
+ *
+ * Now that /dev/vcs exists, most of this can disappear again.
+ */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/uaccess.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/tiocl.h>
+#include <linux/console.h>
+#include <linux/smp_lock.h>
+
+/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
+#define isspace(c)     ((c) == ' ')
+
+extern void poke_blanked_console(void);
+
+/* Variables for selection control. */
+/* Use a dynamic buffer, instead of static (Dec 1994) */
+struct vc_data *sel_cons;              /* must not be deallocated */
+static int use_unicode;
+static volatile int sel_start = -1;    /* cleared by clear_selection */
+static int sel_end;
+static int sel_buffer_lth;
+static char *sel_buffer;
+
+/* clear_selection, highlight and highlight_pointer can be called
+   from interrupt (via scrollback/front) */
+
+/* set reverse video on characters s-e of console with selection. */
+static inline void highlight(const int s, const int e)
+{
+       invert_screen(sel_cons, s, e-s+2, 1);
+}
+
+/* use complementary color to show the pointer */
+static inline void highlight_pointer(const int where)
+{
+       complement_pos(sel_cons, where);
+}
+
+static u16
+sel_pos(int n)
+{
+       return inverse_translate(sel_cons, screen_glyph(sel_cons, n),
+                               use_unicode);
+}
+
+/* remove the current selection highlight, if any,
+   from the console holding the selection. */
+void
+clear_selection(void) {
+       highlight_pointer(-1); /* hide the pointer */
+       if (sel_start != -1) {
+               highlight(sel_start, sel_end);
+               sel_start = -1;
+       }
+}
+
+/*
+ * User settable table: what characters are to be considered alphabetic?
+ * 256 bits
+ */
+static u32 inwordLut[8]={
+  0x00000000, /* control chars     */
+  0x03FF0000, /* digits            */
+  0x87FFFFFE, /* uppercase and '_' */
+  0x07FFFFFE, /* lowercase         */
+  0x00000000,
+  0x00000000,
+  0xFF7FFFFF, /* latin-1 accented letters, not multiplication sign */
+  0xFF7FFFFF  /* latin-1 accented letters, not division sign */
+};
+
+static inline int inword(const u16 c) {
+       return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
+}
+
+/* set inwordLut contents. Invoked by ioctl(). */
+int sel_loadlut(char __user *p)
+{
+       return copy_from_user(inwordLut, (u32 __user *)(p+4), 32) ? -EFAULT : 0;
+}
+
+/* does screen address p correspond to character at LH/RH edge of screen? */
+static inline int atedge(const int p, int size_row)
+{
+       return (!(p % size_row) || !((p + 2) % size_row));
+}
+
+/* constrain v such that v <= u */
+static inline unsigned short limit(const unsigned short v, const unsigned short u)
+{
+       return (v > u) ? u : v;
+}
+
+/* stores the char in UTF8 and returns the number of bytes used (1-3) */
+static int store_utf8(u16 c, char *p)
+{
+       if (c < 0x80) {
+               /*  0******* */
+               p[0] = c;
+               return 1;
+       } else if (c < 0x800) {
+               /* 110***** 10****** */
+               p[0] = 0xc0 | (c >> 6);
+               p[1] = 0x80 | (c & 0x3f);
+               return 2;
+       } else {
+               /* 1110**** 10****** 10****** */
+               p[0] = 0xe0 | (c >> 12);
+               p[1] = 0x80 | ((c >> 6) & 0x3f);
+               p[2] = 0x80 | (c & 0x3f);
+               return 3;
+       }
+}
+
+/* set the current selection. Invoked by ioctl() or by kernel code. */
+int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+       int sel_mode, new_sel_start, new_sel_end, spc;
+       char *bp, *obp;
+       int i, ps, pe, multiplier;
+       u16 c;
+       struct kbd_struct *kbd = kbd_table + fg_console;
+
+       poke_blanked_console();
+
+       { unsigned short xs, ys, xe, ye;
+
+         if (!access_ok(VERIFY_READ, sel, sizeof(*sel)))
+               return -EFAULT;
+         __get_user(xs, &sel->xs);
+         __get_user(ys, &sel->ys);
+         __get_user(xe, &sel->xe);
+         __get_user(ye, &sel->ye);
+         __get_user(sel_mode, &sel->sel_mode);
+         xs--; ys--; xe--; ye--;
+         xs = limit(xs, vc->vc_cols - 1);
+         ys = limit(ys, vc->vc_rows - 1);
+         xe = limit(xe, vc->vc_cols - 1);
+         ye = limit(ye, vc->vc_rows - 1);
+         ps = ys * vc->vc_size_row + (xs << 1);
+         pe = ye * vc->vc_size_row + (xe << 1);
+
+         if (sel_mode == TIOCL_SELCLEAR) {
+             /* useful for screendump without selection highlights */
+             clear_selection();
+             return 0;
+         }
+
+         if (mouse_reporting() && (sel_mode & TIOCL_SELMOUSEREPORT)) {
+             mouse_report(tty, sel_mode & TIOCL_SELBUTTONMASK, xs, ys);
+             return 0;
+         }
+        }
+
+       if (ps > pe)    /* make sel_start <= sel_end */
+       {
+               int tmp = ps;
+               ps = pe;
+               pe = tmp;
+       }
+
+       if (sel_cons != vc_cons[fg_console].d) {
+               clear_selection();
+               sel_cons = vc_cons[fg_console].d;
+       }
+       use_unicode = kbd && kbd->kbdmode == VC_UNICODE;
+
+       switch (sel_mode)
+       {
+               case TIOCL_SELCHAR:     /* character-by-character selection */
+                       new_sel_start = ps;
+                       new_sel_end = pe;
+                       break;
+               case TIOCL_SELWORD:     /* word-by-word selection */
+                       spc = isspace(sel_pos(ps));
+                       for (new_sel_start = ps; ; ps -= 2)
+                       {
+                               if ((spc && !isspace(sel_pos(ps))) ||
+                                   (!spc && !inword(sel_pos(ps))))
+                                       break;
+                               new_sel_start = ps;
+                               if (!(ps % vc->vc_size_row))
+                                       break;
+                       }
+                       spc = isspace(sel_pos(pe));
+                       for (new_sel_end = pe; ; pe += 2)
+                       {
+                               if ((spc && !isspace(sel_pos(pe))) ||
+                                   (!spc && !inword(sel_pos(pe))))
+                                       break;
+                               new_sel_end = pe;
+                               if (!((pe + 2) % vc->vc_size_row))
+                                       break;
+                       }
+                       break;
+               case TIOCL_SELLINE:     /* line-by-line selection */
+                       new_sel_start = ps - ps % vc->vc_size_row;
+                       new_sel_end = pe + vc->vc_size_row
+                                   - pe % vc->vc_size_row - 2;
+                       break;
+               case TIOCL_SELPOINTER:
+                       highlight_pointer(pe);
+                       return 0;
+               default:
+                       return -EINVAL;
+       }
+
+       /* remove the pointer */
+       highlight_pointer(-1);
+
+       /* select to end of line if on trailing space */
+       if (new_sel_end > new_sel_start &&
+               !atedge(new_sel_end, vc->vc_size_row) &&
+               isspace(sel_pos(new_sel_end))) {
+               for (pe = new_sel_end + 2; ; pe += 2)
+                       if (!isspace(sel_pos(pe)) ||
+                           atedge(pe, vc->vc_size_row))
+                               break;
+               if (isspace(sel_pos(pe)))
+                       new_sel_end = pe;
+       }
+       if (sel_start == -1)    /* no current selection */
+               highlight(new_sel_start, new_sel_end);
+       else if (new_sel_start == sel_start)
+       {
+               if (new_sel_end == sel_end)     /* no action required */
+                       return 0;
+               else if (new_sel_end > sel_end) /* extend to right */
+                       highlight(sel_end + 2, new_sel_end);
+               else                            /* contract from right */
+                       highlight(new_sel_end + 2, sel_end);
+       }
+       else if (new_sel_end == sel_end)
+       {
+               if (new_sel_start < sel_start)  /* extend to left */
+                       highlight(new_sel_start, sel_start - 2);
+               else                            /* contract from left */
+                       highlight(sel_start, new_sel_start - 2);
+       }
+       else    /* some other case; start selection from scratch */
+       {
+               clear_selection();
+               highlight(new_sel_start, new_sel_end);
+       }
+       sel_start = new_sel_start;
+       sel_end = new_sel_end;
+
+       /* Allocate a new buffer before freeing the old one ... */
+       multiplier = use_unicode ? 3 : 1;  /* chars can take up to 3 bytes */
+       bp = kmalloc(((sel_end-sel_start)/2+1)*multiplier, GFP_KERNEL);
+       if (!bp) {
+               printk(KERN_WARNING "selection: kmalloc() failed\n");
+               clear_selection();
+               return -ENOMEM;
+       }
+       kfree(sel_buffer);
+       sel_buffer = bp;
+
+       obp = bp;
+       for (i = sel_start; i <= sel_end; i += 2) {
+               c = sel_pos(i);
+               if (use_unicode)
+                       bp += store_utf8(c, bp);
+               else
+                       *bp++ = c;
+               if (!isspace(c))
+                       obp = bp;
+               if (! ((i + 2) % vc->vc_size_row)) {
+                       /* strip trailing blanks from line and add newline,
+                          unless non-space at end of line. */
+                       if (obp != bp) {
+                               bp = obp;
+                               *bp++ = '\r';
+                       }
+                       obp = bp;
+               }
+       }
+       sel_buffer_lth = bp - sel_buffer;
+       return 0;
+}
+
+/* Insert the contents of the selection buffer into the
+ * queue of the tty associated with the current console.
+ * Invoked by ioctl().
+ */
+int paste_selection(struct tty_struct *tty)
+{
+       struct vc_data *vc = tty->driver_data;
+       int     pasted = 0;
+       unsigned int count;
+       struct  tty_ldisc *ld;
+       DECLARE_WAITQUEUE(wait, current);
+
+       /* always called with BTM from vt_ioctl */
+       WARN_ON(!tty_locked());
+
+       acquire_console_sem();
+       poke_blanked_console();
+       release_console_sem();
+
+       ld = tty_ldisc_ref(tty);
+       if (!ld) {
+               tty_unlock();
+               ld = tty_ldisc_ref_wait(tty);
+               tty_lock();
+       }
+
+       add_wait_queue(&vc->paste_wait, &wait);
+       while (sel_buffer && sel_buffer_lth > pasted) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (test_bit(TTY_THROTTLED, &tty->flags)) {
+                       schedule();
+                       continue;
+               }
+               count = sel_buffer_lth - pasted;
+               count = min(count, tty->receive_room);
+               tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
+                                                               NULL, count);
+               pasted += count;
+       }
+       remove_wait_queue(&vc->paste_wait, &wait);
+       __set_current_state(TASK_RUNNING);
+
+       tty_ldisc_deref(ld);
+       return 0;
+}
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c
new file mode 100644 (file)
index 0000000..273ab44
--- /dev/null
@@ -0,0 +1,644 @@
+/*
+ * linux/drivers/char/vc_screen.c
+ *
+ * Provide access to virtual console memory.
+ * /dev/vcs0: the screen as it is being viewed right now (possibly scrolled)
+ * /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63)
+ *            [minor: N]
+ *
+ * /dev/vcsaN: idem, but including attributes, and prefixed with
+ *     the 4 bytes lines,columns,x,y (as screendump used to give).
+ *     Attribute/character pair is in native endianity.
+ *            [minor: N+128]
+ *
+ * This replaces screendump and part of selection, so that the system
+ * administrator can control access using file system permissions.
+ *
+ * aeb@cwi.nl - efter Friedas begravelse - 950211
+ *
+ * machek@k332.feld.cvut.cz - modified not to send characters to wrong console
+ *      - fixed some fatal off-by-one bugs (0-- no longer == -1 -> looping and looping and looping...)
+ *      - making it shorter - scr_readw are macros which expand in PRETTY long code
+ */
+
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/kbd_kern.h>
+#include <linux/console.h>
+#include <linux/device.h>
+#include <linux/smp_lock.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+
+#undef attr
+#undef org
+#undef addr
+#define HEADER_SIZE    4
+
+struct vcs_poll_data {
+       struct notifier_block notifier;
+       unsigned int cons_num;
+       bool seen_last_update;
+       wait_queue_head_t waitq;
+       struct fasync_struct *fasync;
+};
+
+static int
+vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param)
+{
+       struct vt_notifier_param *param = _param;
+       struct vc_data *vc = param->vc;
+       struct vcs_poll_data *poll =
+               container_of(nb, struct vcs_poll_data, notifier);
+       int currcons = poll->cons_num;
+
+       if (code != VT_UPDATE)
+               return NOTIFY_DONE;
+
+       if (currcons == 0)
+               currcons = fg_console;
+       else
+               currcons--;
+       if (currcons != vc->vc_num)
+               return NOTIFY_DONE;
+
+       poll->seen_last_update = false;
+       wake_up_interruptible(&poll->waitq);
+       kill_fasync(&poll->fasync, SIGIO, POLL_IN);
+       return NOTIFY_OK;
+}
+
+static void
+vcs_poll_data_free(struct vcs_poll_data *poll)
+{
+       unregister_vt_notifier(&poll->notifier);
+       kfree(poll);
+}
+
+static struct vcs_poll_data *
+vcs_poll_data_get(struct file *file)
+{
+       struct vcs_poll_data *poll = file->private_data;
+
+       if (poll)
+               return poll;
+
+       poll = kzalloc(sizeof(*poll), GFP_KERNEL);
+       if (!poll)
+               return NULL;
+       poll->cons_num = iminor(file->f_path.dentry->d_inode) & 127;
+       init_waitqueue_head(&poll->waitq);
+       poll->notifier.notifier_call = vcs_notifier;
+       if (register_vt_notifier(&poll->notifier) != 0) {
+               kfree(poll);
+               return NULL;
+       }
+
+       /*
+        * This code may be called either through ->poll() or ->fasync().
+        * If we have two threads using the same file descriptor, they could
+        * both enter this function, both notice that the structure hasn't
+        * been allocated yet and go ahead allocating it in parallel, but
+        * only one of them must survive and be shared otherwise we'd leak
+        * memory with a dangling notifier callback.
+        */
+       spin_lock(&file->f_lock);
+       if (!file->private_data) {
+               file->private_data = poll;
+       } else {
+               /* someone else raced ahead of us */
+               vcs_poll_data_free(poll);
+               poll = file->private_data;
+       }
+       spin_unlock(&file->f_lock);
+
+       return poll;
+}
+
+static int
+vcs_size(struct inode *inode)
+{
+       int size;
+       int minor = iminor(inode);
+       int currcons = minor & 127;
+       struct vc_data *vc;
+
+       if (currcons == 0)
+               currcons = fg_console;
+       else
+               currcons--;
+       if (!vc_cons_allocated(currcons))
+               return -ENXIO;
+       vc = vc_cons[currcons].d;
+
+       size = vc->vc_rows * vc->vc_cols;
+
+       if (minor & 128)
+               size = 2*size + HEADER_SIZE;
+       return size;
+}
+
+static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
+{
+       int size;
+
+       mutex_lock(&con_buf_mtx);
+       size = vcs_size(file->f_path.dentry->d_inode);
+       switch (orig) {
+               default:
+                       mutex_unlock(&con_buf_mtx);
+                       return -EINVAL;
+               case 2:
+                       offset += size;
+                       break;
+               case 1:
+                       offset += file->f_pos;
+               case 0:
+                       break;
+       }
+       if (offset < 0 || offset > size) {
+               mutex_unlock(&con_buf_mtx);
+               return -EINVAL;
+       }
+       file->f_pos = offset;
+       mutex_unlock(&con_buf_mtx);
+       return file->f_pos;
+}
+
+
+static ssize_t
+vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       unsigned int currcons = iminor(inode);
+       struct vc_data *vc;
+       struct vcs_poll_data *poll;
+       long pos;
+       long viewed, attr, read;
+       int col, maxcol;
+       unsigned short *org = NULL;
+       ssize_t ret;
+
+       mutex_lock(&con_buf_mtx);
+
+       pos = *ppos;
+
+       /* Select the proper current console and verify
+        * sanity of the situation under the console lock.
+        */
+       acquire_console_sem();
+
+       attr = (currcons & 128);
+       currcons = (currcons & 127);
+       if (currcons == 0) {
+               currcons = fg_console;
+               viewed = 1;
+       } else {
+               currcons--;
+               viewed = 0;
+       }
+       ret = -ENXIO;
+       if (!vc_cons_allocated(currcons))
+               goto unlock_out;
+       vc = vc_cons[currcons].d;
+
+       ret = -EINVAL;
+       if (pos < 0)
+               goto unlock_out;
+       poll = file->private_data;
+       if (count && poll)
+               poll->seen_last_update = true;
+       read = 0;
+       ret = 0;
+       while (count) {
+               char *con_buf0, *con_buf_start;
+               long this_round, size;
+               ssize_t orig_count;
+               long p = pos;
+
+               /* Check whether we are above size each round,
+                * as copy_to_user at the end of this loop
+                * could sleep.
+                */
+               size = vcs_size(inode);
+               if (pos >= size)
+                       break;
+               if (count > size - pos)
+                       count = size - pos;
+
+               this_round = count;
+               if (this_round > CON_BUF_SIZE)
+                       this_round = CON_BUF_SIZE;
+
+               /* Perform the whole read into the local con_buf.
+                * Then we can drop the console spinlock and safely
+                * attempt to move it to userspace.
+                */
+
+               con_buf_start = con_buf0 = con_buf;
+               orig_count = this_round;
+               maxcol = vc->vc_cols;
+               if (!attr) {
+                       org = screen_pos(vc, p, viewed);
+                       col = p % maxcol;
+                       p += maxcol - col;
+                       while (this_round-- > 0) {
+                               *con_buf0++ = (vcs_scr_readw(vc, org++) & 0xff);
+                               if (++col == maxcol) {
+                                       org = screen_pos(vc, p, viewed);
+                                       col = 0;
+                                       p += maxcol;
+                               }
+                       }
+               } else {
+                       if (p < HEADER_SIZE) {
+                               size_t tmp_count;
+
+                               con_buf0[0] = (char)vc->vc_rows;
+                               con_buf0[1] = (char)vc->vc_cols;
+                               getconsxy(vc, con_buf0 + 2);
+
+                               con_buf_start += p;
+                               this_round += p;
+                               if (this_round > CON_BUF_SIZE) {
+                                       this_round = CON_BUF_SIZE;
+                                       orig_count = this_round - p;
+                               }
+
+                               tmp_count = HEADER_SIZE;
+                               if (tmp_count > this_round)
+                                       tmp_count = this_round;
+
+                               /* Advance state pointers and move on. */
+                               this_round -= tmp_count;
+                               p = HEADER_SIZE;
+                               con_buf0 = con_buf + HEADER_SIZE;
+                               /* If this_round >= 0, then p is even... */
+                       } else if (p & 1) {
+                               /* Skip first byte for output if start address is odd
+                                * Update region sizes up/down depending on free
+                                * space in buffer.
+                                */
+                               con_buf_start++;
+                               if (this_round < CON_BUF_SIZE)
+                                       this_round++;
+                               else
+                                       orig_count--;
+                       }
+                       if (this_round > 0) {
+                               unsigned short *tmp_buf = (unsigned short *)con_buf0;
+
+                               p -= HEADER_SIZE;
+                               p /= 2;
+                               col = p % maxcol;
+
+                               org = screen_pos(vc, p, viewed);
+                               p += maxcol - col;
+
+                               /* Buffer has even length, so we can always copy
+                                * character + attribute. We do not copy last byte
+                                * to userspace if this_round is odd.
+                                */
+                               this_round = (this_round + 1) >> 1;
+
+                               while (this_round) {
+                                       *tmp_buf++ = vcs_scr_readw(vc, org++);
+                                       this_round --;
+                                       if (++col == maxcol) {
+                                               org = screen_pos(vc, p, viewed);
+                                               col = 0;
+                                               p += maxcol;
+                                       }
+                               }
+                       }
+               }
+
+               /* Finally, release the console semaphore while we push
+                * all the data to userspace from our temporary buffer.
+                *
+                * AKPM: Even though it's a semaphore, we should drop it because
+                * the pagefault handling code may want to call printk().
+                */
+
+               release_console_sem();
+               ret = copy_to_user(buf, con_buf_start, orig_count);
+               acquire_console_sem();
+
+               if (ret) {
+                       read += (orig_count - ret);
+                       ret = -EFAULT;
+                       break;
+               }
+               buf += orig_count;
+               pos += orig_count;
+               read += orig_count;
+               count -= orig_count;
+       }
+       *ppos += read;
+       if (read)
+               ret = read;
+unlock_out:
+       release_console_sem();
+       mutex_unlock(&con_buf_mtx);
+       return ret;
+}
+
+static ssize_t
+vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       unsigned int currcons = iminor(inode);
+       struct vc_data *vc;
+       long pos;
+       long viewed, attr, size, written;
+       char *con_buf0;
+       int col, maxcol;
+       u16 *org0 = NULL, *org = NULL;
+       size_t ret;
+
+       mutex_lock(&con_buf_mtx);
+
+       pos = *ppos;
+
+       /* Select the proper current console and verify
+        * sanity of the situation under the console lock.
+        */
+       acquire_console_sem();
+
+       attr = (currcons & 128);
+       currcons = (currcons & 127);
+
+       if (currcons == 0) {
+               currcons = fg_console;
+               viewed = 1;
+       } else {
+               currcons--;
+               viewed = 0;
+       }
+       ret = -ENXIO;
+       if (!vc_cons_allocated(currcons))
+               goto unlock_out;
+       vc = vc_cons[currcons].d;
+
+       size = vcs_size(inode);
+       ret = -EINVAL;
+       if (pos < 0 || pos > size)
+               goto unlock_out;
+       if (count > size - pos)
+               count = size - pos;
+       written = 0;
+       while (count) {
+               long this_round = count;
+               size_t orig_count;
+               long p;
+
+               if (this_round > CON_BUF_SIZE)
+                       this_round = CON_BUF_SIZE;
+
+               /* Temporarily drop the console lock so that we can read
+                * in the write data from userspace safely.
+                */
+               release_console_sem();
+               ret = copy_from_user(con_buf, buf, this_round);
+               acquire_console_sem();
+
+               if (ret) {
+                       this_round -= ret;
+                       if (!this_round) {
+                               /* Abort loop if no data were copied. Otherwise
+                                * fail with -EFAULT.
+                                */
+                               if (written)
+                                       break;
+                               ret = -EFAULT;
+                               goto unlock_out;
+                       }
+               }
+
+               /* The vcs_size might have changed while we slept to grab
+                * the user buffer, so recheck.
+                * Return data written up to now on failure.
+                */
+               size = vcs_size(inode);
+               if (pos >= size)
+                       break;
+               if (this_round > size - pos)
+                       this_round = size - pos;
+
+               /* OK, now actually push the write to the console
+                * under the lock using the local kernel buffer.
+                */
+
+               con_buf0 = con_buf;
+               orig_count = this_round;
+               maxcol = vc->vc_cols;
+               p = pos;
+               if (!attr) {
+                       org0 = org = screen_pos(vc, p, viewed);
+                       col = p % maxcol;
+                       p += maxcol - col;
+
+                       while (this_round > 0) {
+                               unsigned char c = *con_buf0++;
+
+                               this_round--;
+                               vcs_scr_writew(vc,
+                                              (vcs_scr_readw(vc, org) & 0xff00) | c, org);
+                               org++;
+                               if (++col == maxcol) {
+                                       org = screen_pos(vc, p, viewed);
+                                       col = 0;
+                                       p += maxcol;
+                               }
+                       }
+               } else {
+                       if (p < HEADER_SIZE) {
+                               char header[HEADER_SIZE];
+
+                               getconsxy(vc, header + 2);
+                               while (p < HEADER_SIZE && this_round > 0) {
+                                       this_round--;
+                                       header[p++] = *con_buf0++;
+                               }
+                               if (!viewed)
+                                       putconsxy(vc, header + 2);
+                       }
+                       p -= HEADER_SIZE;
+                       col = (p/2) % maxcol;
+                       if (this_round > 0) {
+                               org0 = org = screen_pos(vc, p/2, viewed);
+                               if ((p & 1) && this_round > 0) {
+                                       char c;
+
+                                       this_round--;
+                                       c = *con_buf0++;
+#ifdef __BIG_ENDIAN
+                                       vcs_scr_writew(vc, c |
+                                            (vcs_scr_readw(vc, org) & 0xff00), org);
+#else
+                                       vcs_scr_writew(vc, (c << 8) |
+                                            (vcs_scr_readw(vc, org) & 0xff), org);
+#endif
+                                       org++;
+                                       p++;
+                                       if (++col == maxcol) {
+                                               org = screen_pos(vc, p/2, viewed);
+                                               col = 0;
+                                       }
+                               }
+                               p /= 2;
+                               p += maxcol - col;
+                       }
+                       while (this_round > 1) {
+                               unsigned short w;
+
+                               w = get_unaligned(((unsigned short *)con_buf0));
+                               vcs_scr_writew(vc, w, org++);
+                               con_buf0 += 2;
+                               this_round -= 2;
+                               if (++col == maxcol) {
+                                       org = screen_pos(vc, p, viewed);
+                                       col = 0;
+                                       p += maxcol;
+                               }
+                       }
+                       if (this_round > 0) {
+                               unsigned char c;
+
+                               c = *con_buf0++;
+#ifdef __BIG_ENDIAN
+                               vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff) | (c << 8), org);
+#else
+                               vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff00) | c, org);
+#endif
+                       }
+               }
+               count -= orig_count;
+               written += orig_count;
+               buf += orig_count;
+               pos += orig_count;
+               if (org0)
+                       update_region(vc, (unsigned long)(org0), org - org0);
+       }
+       *ppos += written;
+       ret = written;
+       if (written)
+               vcs_scr_updated(vc);
+
+unlock_out:
+       release_console_sem();
+
+       mutex_unlock(&con_buf_mtx);
+
+       return ret;
+}
+
+static unsigned int
+vcs_poll(struct file *file, poll_table *wait)
+{
+       struct vcs_poll_data *poll = vcs_poll_data_get(file);
+       int ret = 0;
+
+       if (poll) {
+               poll_wait(file, &poll->waitq, wait);
+               if (!poll->seen_last_update)
+                       ret = POLLIN | POLLRDNORM;
+       }
+       return ret;
+}
+
+static int
+vcs_fasync(int fd, struct file *file, int on)
+{
+       struct vcs_poll_data *poll = file->private_data;
+
+       if (!poll) {
+               /* don't allocate anything if all we want is disable fasync */
+               if (!on)
+                       return 0;
+               poll = vcs_poll_data_get(file);
+               if (!poll)
+                       return -ENOMEM;
+       }
+
+       return fasync_helper(fd, file, on, &poll->fasync);
+}
+
+static int
+vcs_open(struct inode *inode, struct file *filp)
+{
+       unsigned int currcons = iminor(inode) & 127;
+       int ret = 0;
+       
+       tty_lock();
+       if(currcons && !vc_cons_allocated(currcons-1))
+               ret = -ENXIO;
+       tty_unlock();
+       return ret;
+}
+
+static int vcs_release(struct inode *inode, struct file *file)
+{
+       struct vcs_poll_data *poll = file->private_data;
+
+       if (poll)
+               vcs_poll_data_free(poll);
+       return 0;
+}
+
+static const struct file_operations vcs_fops = {
+       .llseek         = vcs_lseek,
+       .read           = vcs_read,
+       .write          = vcs_write,
+       .poll           = vcs_poll,
+       .fasync         = vcs_fasync,
+       .open           = vcs_open,
+       .release        = vcs_release,
+};
+
+static struct class *vc_class;
+
+void vcs_make_sysfs(int index)
+{
+       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL,
+                     "vcs%u", index + 1);
+       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL,
+                     "vcsa%u", index + 1);
+}
+
+void vcs_remove_sysfs(int index)
+{
+       device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1));
+       device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129));
+}
+
+int __init vcs_init(void)
+{
+       unsigned int i;
+
+       if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops))
+               panic("unable to get major %d for vcs device", VCS_MAJOR);
+       vc_class = class_create(THIS_MODULE, "vc");
+
+       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
+       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
+       for (i = 0; i < MIN_NR_CONSOLES; i++)
+               vcs_make_sysfs(i);
+       return 0;
+}
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
new file mode 100644 (file)
index 0000000..a8ec48e
--- /dev/null
@@ -0,0 +1,4209 @@
+/*
+ *  linux/drivers/char/vt.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * Hopefully this will be a rather complete VT102 implementation.
+ *
+ * Beeping thanks to John T Kohl.
+ *
+ * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
+ *   Chars, and VT100 enhancements by Peter MacDonald.
+ *
+ * Copy and paste function by Andrew Haylett,
+ *   some enhancements by Alessandro Rubini.
+ *
+ * Code to check for different video-cards mostly by Galen Hunt,
+ * <g-hunt@ee.utah.edu>
+ *
+ * Rudimentary ISO 10646/Unicode/UTF-8 character set support by
+ * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>.
+ *
+ * Dynamic allocation of consoles, aeb@cwi.nl, May 1994
+ * Resizing of consoles, aeb, 940926
+ *
+ * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
+ * <poe@daimi.aau.dk>
+ *
+ * User-defined bell sound, new setterm control sequences and printk
+ * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95
+ *
+ * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
+ *
+ * Merge with the abstract console driver by Geert Uytterhoeven
+ * <geert@linux-m68k.org>, Jan 1997.
+ *
+ *   Original m68k console driver modifications by
+ *
+ *     - Arno Griffioen <arno@usn.nl>
+ *     - David Carter <carter@cs.bris.ac.uk>
+ * 
+ *   The abstract console driver provides a generic interface for a text
+ *   console. It supports VGA text mode, frame buffer based graphical consoles
+ *   and special graphics processors that are only accessible through some
+ *   registers (e.g. a TMS340x0 GSP).
+ *
+ *   The interface to the hardware is specified using a special structure
+ *   (struct consw) which contains function pointers to console operations
+ *   (see <linux/console.h> for more information).
+ *
+ * Support for changeable cursor shape
+ * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997
+ *
+ * Ported to i386 and con_scrolldelta fixed
+ * by Emmanuel Marty <core@ggi-project.org>, April 1998
+ *
+ * Resurrected character buffers in videoram plus lots of other trickery
+ * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
+ *
+ * Removed old-style timers, introduced console_timer, made timer
+ * deletion SMP-safe.  17Jun00, Andrew Morton
+ *
+ * Removed console_lock, enabled interrupts across all console operations
+ * 13 March 2001, Andrew Morton
+ *
+ * Fixed UTF-8 mode so alternate charset modes always work according
+ * to control sequences interpreted in do_con_trol function
+ * preserving backward VT100 semigraphics compatibility,
+ * malformed UTF sequences represented as sequences of replacement glyphs,
+ * original codes or '?' as a last resort if replacement glyph is undefined
+ * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kd.h>
+#include <linux/slab.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/smp_lock.h>
+#include <linux/tiocl.h>
+#include <linux/kbd_kern.h>
+#include <linux/consolemap.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/pm.h>
+#include <linux/font.h>
+#include <linux/bitops.h>
+#include <linux/notifier.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <asm/system.h>
+#include <linux/uaccess.h>
+#include <linux/kdb.h>
+#include <linux/ctype.h>
+
+#define MAX_NR_CON_DRIVER 16
+
+#define CON_DRIVER_FLAG_MODULE 1
+#define CON_DRIVER_FLAG_INIT   2
+#define CON_DRIVER_FLAG_ATTR   4
+
+struct con_driver {
+       const struct consw *con;
+       const char *desc;
+       struct device *dev;
+       int node;
+       int first;
+       int last;
+       int flag;
+};
+
+static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER];
+const struct consw *conswitchp;
+
+/* A bitmap for codes <32. A bit of 1 indicates that the code
+ * corresponding to that bit number invokes some special action
+ * (such as cursor movement) and should not be displayed as a
+ * glyph unless the disp_ctrl mode is explicitly enabled.
+ */
+#define CTRL_ACTION 0x0d00ff81
+#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */
+
+/*
+ * Here is the default bell parameters: 750HZ, 1/8th of a second
+ */
+#define DEFAULT_BELL_PITCH     750
+#define DEFAULT_BELL_DURATION  (HZ/8)
+
+struct vc vc_cons [MAX_NR_CONSOLES];
+
+#ifndef VT_SINGLE_DRIVER
+static const struct consw *con_driver_map[MAX_NR_CONSOLES];
+#endif
+
+static int con_open(struct tty_struct *, struct file *);
+static void vc_init(struct vc_data *vc, unsigned int rows,
+                   unsigned int cols, int do_clear);
+static void gotoxy(struct vc_data *vc, int new_x, int new_y);
+static void save_cur(struct vc_data *vc);
+static void reset_terminal(struct vc_data *vc, int do_clear);
+static void con_flush_chars(struct tty_struct *tty);
+static int set_vesa_blanking(char __user *p);
+static void set_cursor(struct vc_data *vc);
+static void hide_cursor(struct vc_data *vc);
+static void console_callback(struct work_struct *ignored);
+static void blank_screen_t(unsigned long dummy);
+static void set_palette(struct vc_data *vc);
+
+static int printable;          /* Is console ready for printing? */
+int default_utf8 = true;
+module_param(default_utf8, int, S_IRUGO | S_IWUSR);
+int global_cursor_default = -1;
+module_param(global_cursor_default, int, S_IRUGO | S_IWUSR);
+
+static int cur_default = CUR_DEFAULT;
+module_param(cur_default, int, S_IRUGO | S_IWUSR);
+
+/*
+ * ignore_poke: don't unblank the screen when things are typed.  This is
+ * mainly for the privacy of braille terminal users.
+ */
+static int ignore_poke;
+
+int do_poke_blanked_console;
+int console_blanked;
+
+static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
+static int vesa_off_interval;
+static int blankinterval = 10*60;
+core_param(consoleblank, blankinterval, int, 0444);
+
+static DECLARE_WORK(console_work, console_callback);
+
+/*
+ * fg_console is the current virtual console,
+ * last_console is the last used one,
+ * want_console is the console we want to switch to,
+ * saved_* variants are for save/restore around kernel debugger enter/leave
+ */
+int fg_console;
+int last_console;
+int want_console = -1;
+static int saved_fg_console;
+static int saved_last_console;
+static int saved_want_console;
+static int saved_vc_mode;
+static int saved_console_blanked;
+
+/*
+ * For each existing display, we have a pointer to console currently visible
+ * on that display, allowing consoles other than fg_console to be refreshed
+ * appropriately. Unless the low-level driver supplies its own display_fg
+ * variable, we use this one for the "master display".
+ */
+static struct vc_data *master_display_fg;
+
+/*
+ * Unfortunately, we need to delay tty echo when we're currently writing to the
+ * console since the code is (and always was) not re-entrant, so we schedule
+ * all flip requests to process context with schedule-task() and run it from
+ * console_callback().
+ */
+
+/*
+ * For the same reason, we defer scrollback to the console callback.
+ */
+static int scrollback_delta;
+
+/*
+ * Hook so that the power management routines can (un)blank
+ * the console on our behalf.
+ */
+int (*console_blank_hook)(int);
+
+static DEFINE_TIMER(console_timer, blank_screen_t, 0, 0);
+static int blank_state;
+static int blank_timer_expired;
+enum {
+       blank_off = 0,
+       blank_normal_wait,
+       blank_vesa_wait,
+};
+
+/*
+ * Notifier list for console events.
+ */
+static ATOMIC_NOTIFIER_HEAD(vt_notifier_list);
+
+int register_vt_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_register(&vt_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(register_vt_notifier);
+
+int unregister_vt_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_unregister(&vt_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_vt_notifier);
+
+static void notify_write(struct vc_data *vc, unsigned int unicode)
+{
+       struct vt_notifier_param param = { .vc = vc, unicode = unicode };
+       atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, &param);
+}
+
+static void notify_update(struct vc_data *vc)
+{
+       struct vt_notifier_param param = { .vc = vc };
+       atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, &param);
+}
+/*
+ *     Low-Level Functions
+ */
+
+#define IS_FG(vc)      ((vc)->vc_num == fg_console)
+
+#ifdef VT_BUF_VRAM_ONLY
+#define DO_UPDATE(vc)  0
+#else
+#define DO_UPDATE(vc)  (CON_IS_VISIBLE(vc) && !console_blanked)
+#endif
+
+static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
+{
+       unsigned short *p;
+       
+       if (!viewed)
+               p = (unsigned short *)(vc->vc_origin + offset);
+       else if (!vc->vc_sw->con_screen_pos)
+               p = (unsigned short *)(vc->vc_visible_origin + offset);
+       else
+               p = vc->vc_sw->con_screen_pos(vc, offset);
+       return p;
+}
+
+/* Called  from the keyboard irq path.. */
+static inline void scrolldelta(int lines)
+{
+       /* FIXME */
+       /* scrolldelta needs some kind of consistency lock, but the BKL was
+          and still is not protecting versus the scheduled back end */
+       scrollback_delta += lines;
+       schedule_console_callback();
+}
+
+void schedule_console_callback(void)
+{
+       schedule_work(&console_work);
+}
+
+static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
+{
+       unsigned short *d, *s;
+
+       if (t+nr >= b)
+               nr = b - t - 1;
+       if (b > vc->vc_rows || t >= b || nr < 1)
+               return;
+       if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr))
+               return;
+       d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
+       s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
+       scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
+       scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
+                   vc->vc_size_row * nr);
+}
+
+static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
+{
+       unsigned short *s;
+       unsigned int step;
+
+       if (t+nr >= b)
+               nr = b - t - 1;
+       if (b > vc->vc_rows || t >= b || nr < 1)
+               return;
+       if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr))
+               return;
+       s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
+       step = vc->vc_cols * nr;
+       scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
+       scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
+}
+
+static void do_update_region(struct vc_data *vc, unsigned long start, int count)
+{
+#ifndef VT_BUF_VRAM_ONLY
+       unsigned int xx, yy, offset;
+       u16 *p;
+
+       p = (u16 *) start;
+       if (!vc->vc_sw->con_getxy) {
+               offset = (start - vc->vc_origin) / 2;
+               xx = offset % vc->vc_cols;
+               yy = offset / vc->vc_cols;
+       } else {
+               int nxx, nyy;
+               start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy);
+               xx = nxx; yy = nyy;
+       }
+       for(;;) {
+               u16 attrib = scr_readw(p) & 0xff00;
+               int startx = xx;
+               u16 *q = p;
+               while (xx < vc->vc_cols && count) {
+                       if (attrib != (scr_readw(p) & 0xff00)) {
+                               if (p > q)
+                                       vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
+                               startx = xx;
+                               q = p;
+                               attrib = scr_readw(p) & 0xff00;
+                       }
+                       p++;
+                       xx++;
+                       count--;
+               }
+               if (p > q)
+                       vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
+               if (!count)
+                       break;
+               xx = 0;
+               yy++;
+               if (vc->vc_sw->con_getxy) {
+                       p = (u16 *)start;
+                       start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
+               }
+       }
+#endif
+}
+
+void update_region(struct vc_data *vc, unsigned long start, int count)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (DO_UPDATE(vc)) {
+               hide_cursor(vc);
+               do_update_region(vc, start, count);
+               set_cursor(vc);
+       }
+}
+
+/* Structure of attributes is hardware-dependent */
+
+static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
+    u8 _underline, u8 _reverse, u8 _italic)
+{
+       if (vc->vc_sw->con_build_attr)
+               return vc->vc_sw->con_build_attr(vc, _color, _intensity,
+                      _blink, _underline, _reverse, _italic);
+
+#ifndef VT_BUF_VRAM_ONLY
+/*
+ * ++roman: I completely changed the attribute format for monochrome
+ * mode (!can_do_color). The formerly used MDA (monochrome display
+ * adapter) format didn't allow the combination of certain effects.
+ * Now the attribute is just a bit vector:
+ *  Bit 0..1: intensity (0..2)
+ *  Bit 2   : underline
+ *  Bit 3   : reverse
+ *  Bit 7   : blink
+ */
+       {
+       u8 a = _color;
+       if (!vc->vc_can_do_color)
+               return _intensity |
+                      (_italic ? 2 : 0) |
+                      (_underline ? 4 : 0) |
+                      (_reverse ? 8 : 0) |
+                      (_blink ? 0x80 : 0);
+       if (_italic)
+               a = (a & 0xF0) | vc->vc_itcolor;
+       else if (_underline)
+               a = (a & 0xf0) | vc->vc_ulcolor;
+       else if (_intensity == 0)
+               a = (a & 0xf0) | vc->vc_ulcolor;
+       if (_reverse)
+               a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
+       if (_blink)
+               a ^= 0x80;
+       if (_intensity == 2)
+               a ^= 0x08;
+       if (vc->vc_hi_font_mask == 0x100)
+               a <<= 1;
+       return a;
+       }
+#else
+       return 0;
+#endif
+}
+
+static void update_attr(struct vc_data *vc)
+{
+       vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity,
+                     vc->vc_blink, vc->vc_underline,
+                     vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
+       vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
+}
+
+/* Note: inverting the screen twice should revert to the original state */
+void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
+{
+       unsigned short *p;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       count /= 2;
+       p = screenpos(vc, offset, viewed);
+       if (vc->vc_sw->con_invert_region)
+               vc->vc_sw->con_invert_region(vc, p, count);
+#ifndef VT_BUF_VRAM_ONLY
+       else {
+               u16 *q = p;
+               int cnt = count;
+               u16 a;
+
+               if (!vc->vc_can_do_color) {
+                       while (cnt--) {
+                           a = scr_readw(q);
+                           a ^= 0x0800;
+                           scr_writew(a, q);
+                           q++;
+                       }
+               } else if (vc->vc_hi_font_mask == 0x100) {
+                       while (cnt--) {
+                               a = scr_readw(q);
+                               a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
+                               scr_writew(a, q);
+                               q++;
+                       }
+               } else {
+                       while (cnt--) {
+                               a = scr_readw(q);
+                               a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
+                               scr_writew(a, q);
+                               q++;
+                       }
+               }
+       }
+#endif
+       if (DO_UPDATE(vc))
+               do_update_region(vc, (unsigned long) p, count);
+}
+
+/* used by selection: complement pointer position */
+void complement_pos(struct vc_data *vc, int offset)
+{
+       static int old_offset = -1;
+       static unsigned short old;
+       static unsigned short oldx, oldy;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       if (old_offset != -1 && old_offset >= 0 &&
+           old_offset < vc->vc_screenbuf_size) {
+               scr_writew(old, screenpos(vc, old_offset, 1));
+               if (DO_UPDATE(vc))
+                       vc->vc_sw->con_putc(vc, old, oldy, oldx);
+       }
+
+       old_offset = offset;
+
+       if (offset != -1 && offset >= 0 &&
+           offset < vc->vc_screenbuf_size) {
+               unsigned short new;
+               unsigned short *p;
+               p = screenpos(vc, offset, 1);
+               old = scr_readw(p);
+               new = old ^ vc->vc_complement_mask;
+               scr_writew(new, p);
+               if (DO_UPDATE(vc)) {
+                       oldx = (offset >> 1) % vc->vc_cols;
+                       oldy = (offset >> 1) / vc->vc_cols;
+                       vc->vc_sw->con_putc(vc, new, oldy, oldx);
+               }
+       }
+
+}
+
+static void insert_char(struct vc_data *vc, unsigned int nr)
+{
+       unsigned short *p, *q = (unsigned short *)vc->vc_pos;
+
+       p = q + vc->vc_cols - nr - vc->vc_x;
+       while (--p >= q)
+               scr_writew(scr_readw(p), p + nr);
+       scr_memsetw(q, vc->vc_video_erase_char, nr * 2);
+       vc->vc_need_wrap = 0;
+       if (DO_UPDATE(vc)) {
+               unsigned short oldattr = vc->vc_attr;
+               vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1,
+                                    vc->vc_cols - vc->vc_x - nr);
+               vc->vc_attr = vc->vc_video_erase_char >> 8;
+               while (nr--)
+                       vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr);
+               vc->vc_attr = oldattr;
+       }
+}
+
+static void delete_char(struct vc_data *vc, unsigned int nr)
+{
+       unsigned int i = vc->vc_x;
+       unsigned short *p = (unsigned short *)vc->vc_pos;
+
+       while (++i <= vc->vc_cols - nr) {
+               scr_writew(scr_readw(p+nr), p);
+               p++;
+       }
+       scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
+       vc->vc_need_wrap = 0;
+       if (DO_UPDATE(vc)) {
+               unsigned short oldattr = vc->vc_attr;
+               vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1,
+                                    vc->vc_cols - vc->vc_x - nr);
+               vc->vc_attr = vc->vc_video_erase_char >> 8;
+               while (nr--)
+                       vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y,
+                                    vc->vc_cols - 1 - nr);
+               vc->vc_attr = oldattr;
+       }
+}
+
+static int softcursor_original;
+
+static void add_softcursor(struct vc_data *vc)
+{
+       int i = scr_readw((u16 *) vc->vc_pos);
+       u32 type = vc->vc_cursor_type;
+
+       if (! (type & 0x10)) return;
+       if (softcursor_original != -1) return;
+       softcursor_original = i;
+       i |= ((type >> 8) & 0xff00 );
+       i ^= ((type) & 0xff00 );
+       if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
+       if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
+       scr_writew(i, (u16 *) vc->vc_pos);
+       if (DO_UPDATE(vc))
+               vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x);
+}
+
+static void hide_softcursor(struct vc_data *vc)
+{
+       if (softcursor_original != -1) {
+               scr_writew(softcursor_original, (u16 *)vc->vc_pos);
+               if (DO_UPDATE(vc))
+                       vc->vc_sw->con_putc(vc, softcursor_original,
+                                       vc->vc_y, vc->vc_x);
+               softcursor_original = -1;
+       }
+}
+
+static void hide_cursor(struct vc_data *vc)
+{
+       if (vc == sel_cons)
+               clear_selection();
+       vc->vc_sw->con_cursor(vc, CM_ERASE);
+       hide_softcursor(vc);
+}
+
+static void set_cursor(struct vc_data *vc)
+{
+       if (!IS_FG(vc) || console_blanked ||
+           vc->vc_mode == KD_GRAPHICS)
+               return;
+       if (vc->vc_deccm) {
+               if (vc == sel_cons)
+                       clear_selection();
+               add_softcursor(vc);
+               if ((vc->vc_cursor_type & 0x0f) != 1)
+                       vc->vc_sw->con_cursor(vc, CM_DRAW);
+       } else
+               hide_cursor(vc);
+}
+
+static void set_origin(struct vc_data *vc)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (!CON_IS_VISIBLE(vc) ||
+           !vc->vc_sw->con_set_origin ||
+           !vc->vc_sw->con_set_origin(vc))
+               vc->vc_origin = (unsigned long)vc->vc_screenbuf;
+       vc->vc_visible_origin = vc->vc_origin;
+       vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
+       vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
+}
+
+static inline void save_screen(struct vc_data *vc)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (vc->vc_sw->con_save_screen)
+               vc->vc_sw->con_save_screen(vc);
+}
+
+/*
+ *     Redrawing of screen
+ */
+
+static void clear_buffer_attributes(struct vc_data *vc)
+{
+       unsigned short *p = (unsigned short *)vc->vc_origin;
+       int count = vc->vc_screenbuf_size / 2;
+       int mask = vc->vc_hi_font_mask | 0xff;
+
+       for (; count > 0; count--, p++) {
+               scr_writew((scr_readw(p)&mask) | (vc->vc_video_erase_char & ~mask), p);
+       }
+}
+
+void redraw_screen(struct vc_data *vc, int is_switch)
+{
+       int redraw = 0;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       if (!vc) {
+               /* strange ... */
+               /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
+               return;
+       }
+
+       if (is_switch) {
+               struct vc_data *old_vc = vc_cons[fg_console].d;
+               if (old_vc == vc)
+                       return;
+               if (!CON_IS_VISIBLE(vc))
+                       redraw = 1;
+               *vc->vc_display_fg = vc;
+               fg_console = vc->vc_num;
+               hide_cursor(old_vc);
+               if (!CON_IS_VISIBLE(old_vc)) {
+                       save_screen(old_vc);
+                       set_origin(old_vc);
+               }
+       } else {
+               hide_cursor(vc);
+               redraw = 1;
+       }
+
+       if (redraw) {
+               int update;
+               int old_was_color = vc->vc_can_do_color;
+
+               set_origin(vc);
+               update = vc->vc_sw->con_switch(vc);
+               set_palette(vc);
+               /*
+                * If console changed from mono<->color, the best we can do
+                * is to clear the buffer attributes. As it currently stands,
+                * rebuilding new attributes from the old buffer is not doable
+                * without overly complex code.
+                */
+               if (old_was_color != vc->vc_can_do_color) {
+                       update_attr(vc);
+                       clear_buffer_attributes(vc);
+               }
+
+               /* Forcibly update if we're panicing */
+               if ((update && vc->vc_mode != KD_GRAPHICS) ||
+                   vt_force_oops_output(vc))
+                       do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
+       }
+       set_cursor(vc);
+       if (is_switch) {
+               set_leds();
+               compute_shiftstate();
+               notify_update(vc);
+       }
+}
+
+/*
+ *     Allocation, freeing and resizing of VTs.
+ */
+
+int vc_cons_allocated(unsigned int i)
+{
+       return (i < MAX_NR_CONSOLES && vc_cons[i].d);
+}
+
+static void visual_init(struct vc_data *vc, int num, int init)
+{
+       /* ++Geert: vc->vc_sw->con_init determines console size */
+       if (vc->vc_sw)
+               module_put(vc->vc_sw->owner);
+       vc->vc_sw = conswitchp;
+#ifndef VT_SINGLE_DRIVER
+       if (con_driver_map[num])
+               vc->vc_sw = con_driver_map[num];
+#endif
+       __module_get(vc->vc_sw->owner);
+       vc->vc_num = num;
+       vc->vc_display_fg = &master_display_fg;
+       vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
+       vc->vc_uni_pagedir = 0;
+       vc->vc_hi_font_mask = 0;
+       vc->vc_complement_mask = 0;
+       vc->vc_can_do_color = 0;
+       vc->vc_panic_force_write = false;
+       vc->vc_sw->con_init(vc, init);
+       if (!vc->vc_complement_mask)
+               vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
+       vc->vc_s_complement_mask = vc->vc_complement_mask;
+       vc->vc_size_row = vc->vc_cols << 1;
+       vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
+}
+
+int vc_allocate(unsigned int currcons) /* return 0 on success */
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (currcons >= MAX_NR_CONSOLES)
+               return -ENXIO;
+       if (!vc_cons[currcons].d) {
+           struct vc_data *vc;
+           struct vt_notifier_param param;
+
+           /* prevent users from taking too much memory */
+           if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
+             return -EPERM;
+
+           /* due to the granularity of kmalloc, we waste some memory here */
+           /* the alloc is done in two steps, to optimize the common situation
+              of a 25x80 console (structsize=216, screenbuf_size=4000) */
+           /* although the numbers above are not valid since long ago, the
+              point is still up-to-date and the comment still has its value
+              even if only as a historical artifact.  --mj, July 1998 */
+           param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
+           if (!vc)
+               return -ENOMEM;
+           vc_cons[currcons].d = vc;
+           tty_port_init(&vc->port);
+           INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
+           visual_init(vc, currcons, 1);
+           if (!*vc->vc_uni_pagedir_loc)
+               con_set_default_unimap(vc);
+           vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
+           if (!vc->vc_screenbuf) {
+               kfree(vc);
+               vc_cons[currcons].d = NULL;
+               return -ENOMEM;
+           }
+
+           /* If no drivers have overridden us and the user didn't pass a
+              boot option, default to displaying the cursor */
+           if (global_cursor_default == -1)
+                   global_cursor_default = 1;
+
+           vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
+           vcs_make_sysfs(currcons);
+           atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
+       }
+       return 0;
+}
+
+static inline int resize_screen(struct vc_data *vc, int width, int height,
+                               int user)
+{
+       /* Resizes the resolution of the display adapater */
+       int err = 0;
+
+       if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize)
+               err = vc->vc_sw->con_resize(vc, width, height, user);
+
+       return err;
+}
+
+/*
+ * Change # of rows and columns (0 means unchanged/the size of fg_console)
+ * [this is to be used together with some user program
+ * like resize that changes the hardware videomode]
+ */
+#define VC_RESIZE_MAXCOL (32767)
+#define VC_RESIZE_MAXROW (32767)
+
+/**
+ *     vc_do_resize    -       resizing method for the tty
+ *     @tty: tty being resized
+ *     @real_tty: real tty (different to tty if a pty/tty pair)
+ *     @vc: virtual console private data
+ *     @cols: columns
+ *     @lines: lines
+ *
+ *     Resize a virtual console, clipping according to the actual constraints.
+ *     If the caller passes a tty structure then update the termios winsize
+ *     information and perform any necessary signal handling.
+ *
+ *     Caller must hold the console semaphore. Takes the termios mutex and
+ *     ctrl_lock of the tty IFF a tty is passed.
+ */
+
+static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
+                               unsigned int cols, unsigned int lines)
+{
+       unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
+       unsigned long end;
+       unsigned int old_cols, old_rows, old_row_size, old_screen_size;
+       unsigned int new_cols, new_rows, new_row_size, new_screen_size;
+       unsigned int user;
+       unsigned short *newscreen;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       if (!vc)
+               return -ENXIO;
+
+       user = vc->vc_resize_user;
+       vc->vc_resize_user = 0;
+
+       if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
+               return -EINVAL;
+
+       new_cols = (cols ? cols : vc->vc_cols);
+       new_rows = (lines ? lines : vc->vc_rows);
+       new_row_size = new_cols << 1;
+       new_screen_size = new_row_size * new_rows;
+
+       if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
+               return 0;
+
+       newscreen = kmalloc(new_screen_size, GFP_USER);
+       if (!newscreen)
+               return -ENOMEM;
+
+       old_rows = vc->vc_rows;
+       old_cols = vc->vc_cols;
+       old_row_size = vc->vc_size_row;
+       old_screen_size = vc->vc_screenbuf_size;
+
+       err = resize_screen(vc, new_cols, new_rows, user);
+       if (err) {
+               kfree(newscreen);
+               return err;
+       }
+
+       vc->vc_rows = new_rows;
+       vc->vc_cols = new_cols;
+       vc->vc_size_row = new_row_size;
+       vc->vc_screenbuf_size = new_screen_size;
+
+       rlth = min(old_row_size, new_row_size);
+       rrem = new_row_size - rlth;
+       old_origin = vc->vc_origin;
+       new_origin = (long) newscreen;
+       new_scr_end = new_origin + new_screen_size;
+
+       if (vc->vc_y > new_rows) {
+               if (old_rows - vc->vc_y < new_rows) {
+                       /*
+                        * Cursor near the bottom, copy contents from the
+                        * bottom of buffer
+                        */
+                       old_origin += (old_rows - new_rows) * old_row_size;
+               } else {
+                       /*
+                        * Cursor is in no man's land, copy 1/2 screenful
+                        * from the top and bottom of cursor position
+                        */
+                       old_origin += (vc->vc_y - new_rows/2) * old_row_size;
+               }
+       }
+
+       end = old_origin + old_row_size * min(old_rows, new_rows);
+
+       update_attr(vc);
+
+       while (old_origin < end) {
+               scr_memcpyw((unsigned short *) new_origin,
+                           (unsigned short *) old_origin, rlth);
+               if (rrem)
+                       scr_memsetw((void *)(new_origin + rlth),
+                                   vc->vc_video_erase_char, rrem);
+               old_origin += old_row_size;
+               new_origin += new_row_size;
+       }
+       if (new_scr_end > new_origin)
+               scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
+                           new_scr_end - new_origin);
+       kfree(vc->vc_screenbuf);
+       vc->vc_screenbuf = newscreen;
+       vc->vc_screenbuf_size = new_screen_size;
+       set_origin(vc);
+
+       /* do part of a reset_terminal() */
+       vc->vc_top = 0;
+       vc->vc_bottom = vc->vc_rows;
+       gotoxy(vc, vc->vc_x, vc->vc_y);
+       save_cur(vc);
+
+       if (tty) {
+               /* Rewrite the requested winsize data with the actual
+                  resulting sizes */
+               struct winsize ws;
+               memset(&ws, 0, sizeof(ws));
+               ws.ws_row = vc->vc_rows;
+               ws.ws_col = vc->vc_cols;
+               ws.ws_ypixel = vc->vc_scan_lines;
+               tty_do_resize(tty, &ws);
+       }
+
+       if (CON_IS_VISIBLE(vc))
+               update_screen(vc);
+       vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
+       return err;
+}
+
+/**
+ *     vc_resize               -       resize a VT
+ *     @vc: virtual console
+ *     @cols: columns
+ *     @rows: rows
+ *
+ *     Resize a virtual console as seen from the console end of things. We
+ *     use the common vc_do_resize methods to update the structures. The
+ *     caller must hold the console sem to protect console internals and
+ *     vc->port.tty
+ */
+
+int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
+{
+       return vc_do_resize(vc->port.tty, vc, cols, rows);
+}
+
+/**
+ *     vt_resize               -       resize a VT
+ *     @tty: tty to resize
+ *     @ws: winsize attributes
+ *
+ *     Resize a virtual terminal. This is called by the tty layer as we
+ *     register our own handler for resizing. The mutual helper does all
+ *     the actual work.
+ *
+ *     Takes the console sem and the called methods then take the tty
+ *     termios_mutex and the tty ctrl_lock in that order.
+ */
+static int vt_resize(struct tty_struct *tty, struct winsize *ws)
+{
+       struct vc_data *vc = tty->driver_data;
+       int ret;
+
+       acquire_console_sem();
+       ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row);
+       release_console_sem();
+       return ret;
+}
+
+void vc_deallocate(unsigned int currcons)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (vc_cons_allocated(currcons)) {
+               struct vc_data *vc = vc_cons[currcons].d;
+               struct vt_notifier_param param = { .vc = vc };
+
+               atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param);
+               vcs_remove_sysfs(currcons);
+               vc->vc_sw->con_deinit(vc);
+               put_pid(vc->vt_pid);
+               module_put(vc->vc_sw->owner);
+               kfree(vc->vc_screenbuf);
+               if (currcons >= MIN_NR_CONSOLES)
+                       kfree(vc);
+               vc_cons[currcons].d = NULL;
+       }
+}
+
+/*
+ *     VT102 emulator
+ */
+
+#define set_kbd(vc, x) set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
+#define clr_kbd(vc, x) clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
+#define is_kbd(vc, x)  vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
+
+#define decarm         VC_REPEAT
+#define decckm         VC_CKMODE
+#define kbdapplic      VC_APPLIC
+#define lnm            VC_CRLF
+
+/*
+ * this is what the terminal answers to a ESC-Z or csi0c query.
+ */
+#define VT100ID "\033[?1;2c"
+#define VT102ID "\033[?6c"
+
+unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
+                                      8,12,10,14, 9,13,11,15 };
+
+/* the default colour table, for VGA+ colour systems */
+int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
+    0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
+int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
+    0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
+int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
+    0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
+
+module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR);
+module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR);
+module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR);
+
+/*
+ * gotoxy() must verify all boundaries, because the arguments
+ * might also be negative. If the given position is out of
+ * bounds, the cursor is placed at the nearest margin.
+ */
+static void gotoxy(struct vc_data *vc, int new_x, int new_y)
+{
+       int min_y, max_y;
+
+       if (new_x < 0)
+               vc->vc_x = 0;
+       else {
+               if (new_x >= vc->vc_cols)
+                       vc->vc_x = vc->vc_cols - 1;
+               else
+                       vc->vc_x = new_x;
+       }
+
+       if (vc->vc_decom) {
+               min_y = vc->vc_top;
+               max_y = vc->vc_bottom;
+       } else {
+               min_y = 0;
+               max_y = vc->vc_rows;
+       }
+       if (new_y < min_y)
+               vc->vc_y = min_y;
+       else if (new_y >= max_y)
+               vc->vc_y = max_y - 1;
+       else
+               vc->vc_y = new_y;
+       vc->vc_pos = vc->vc_origin + vc->vc_y * vc->vc_size_row + (vc->vc_x<<1);
+       vc->vc_need_wrap = 0;
+}
+
+/* for absolute user moves, when decom is set */
+static void gotoxay(struct vc_data *vc, int new_x, int new_y)
+{
+       gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y);
+}
+
+void scrollback(struct vc_data *vc, int lines)
+{
+       if (!lines)
+               lines = vc->vc_rows / 2;
+       scrolldelta(-lines);
+}
+
+void scrollfront(struct vc_data *vc, int lines)
+{
+       if (!lines)
+               lines = vc->vc_rows / 2;
+       scrolldelta(lines);
+}
+
+static void lf(struct vc_data *vc)
+{
+       /* don't scroll if above bottom of scrolling region, or
+        * if below scrolling region
+        */
+       if (vc->vc_y + 1 == vc->vc_bottom)
+               scrup(vc, vc->vc_top, vc->vc_bottom, 1);
+       else if (vc->vc_y < vc->vc_rows - 1) {
+               vc->vc_y++;
+               vc->vc_pos += vc->vc_size_row;
+       }
+       vc->vc_need_wrap = 0;
+       notify_write(vc, '\n');
+}
+
+static void ri(struct vc_data *vc)
+{
+       /* don't scroll if below top of scrolling region, or
+        * if above scrolling region
+        */
+       if (vc->vc_y == vc->vc_top)
+               scrdown(vc, vc->vc_top, vc->vc_bottom, 1);
+       else if (vc->vc_y > 0) {
+               vc->vc_y--;
+               vc->vc_pos -= vc->vc_size_row;
+       }
+       vc->vc_need_wrap = 0;
+}
+
+static inline void cr(struct vc_data *vc)
+{
+       vc->vc_pos -= vc->vc_x << 1;
+       vc->vc_need_wrap = vc->vc_x = 0;
+       notify_write(vc, '\r');
+}
+
+static inline void bs(struct vc_data *vc)
+{
+       if (vc->vc_x) {
+               vc->vc_pos -= 2;
+               vc->vc_x--;
+               vc->vc_need_wrap = 0;
+               notify_write(vc, '\b');
+       }
+}
+
+static inline void del(struct vc_data *vc)
+{
+       /* ignored */
+}
+
+static void csi_J(struct vc_data *vc, int vpar)
+{
+       unsigned int count;
+       unsigned short * start;
+
+       switch (vpar) {
+               case 0: /* erase from cursor to end of display */
+                       count = (vc->vc_scr_end - vc->vc_pos) >> 1;
+                       start = (unsigned short *)vc->vc_pos;
+                       if (DO_UPDATE(vc)) {
+                               /* do in two stages */
+                               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
+                                             vc->vc_cols - vc->vc_x);
+                               vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0,
+                                             vc->vc_rows - vc->vc_y - 1,
+                                             vc->vc_cols);
+                       }
+                       break;
+               case 1: /* erase from start to cursor */
+                       count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
+                       start = (unsigned short *)vc->vc_origin;
+                       if (DO_UPDATE(vc)) {
+                               /* do in two stages */
+                               vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y,
+                                             vc->vc_cols);
+                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
+                                             vc->vc_x + 1);
+                       }
+                       break;
+               case 2: /* erase whole display */
+                       count = vc->vc_cols * vc->vc_rows;
+                       start = (unsigned short *)vc->vc_origin;
+                       if (DO_UPDATE(vc))
+                               vc->vc_sw->con_clear(vc, 0, 0,
+                                             vc->vc_rows,
+                                             vc->vc_cols);
+                       break;
+               default:
+                       return;
+       }
+       scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
+       vc->vc_need_wrap = 0;
+}
+
+static void csi_K(struct vc_data *vc, int vpar)
+{
+       unsigned int count;
+       unsigned short * start;
+
+       switch (vpar) {
+               case 0: /* erase from cursor to end of line */
+                       count = vc->vc_cols - vc->vc_x;
+                       start = (unsigned short *)vc->vc_pos;
+                       if (DO_UPDATE(vc))
+                               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
+                                                    vc->vc_cols - vc->vc_x);
+                       break;
+               case 1: /* erase from start of line to cursor */
+                       start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
+                       count = vc->vc_x + 1;
+                       if (DO_UPDATE(vc))
+                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
+                                                    vc->vc_x + 1);
+                       break;
+               case 2: /* erase whole line */
+                       start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
+                       count = vc->vc_cols;
+                       if (DO_UPDATE(vc))
+                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
+                                             vc->vc_cols);
+                       break;
+               default:
+                       return;
+       }
+       scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
+       vc->vc_need_wrap = 0;
+}
+
+static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */
+{                                        /* not vt100? */
+       int count;
+
+       if (!vpar)
+               vpar++;
+       count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar;
+
+       scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
+       if (DO_UPDATE(vc))
+               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count);
+       vc->vc_need_wrap = 0;
+}
+
+static void default_attr(struct vc_data *vc)
+{
+       vc->vc_intensity = 1;
+       vc->vc_italic = 0;
+       vc->vc_underline = 0;
+       vc->vc_reverse = 0;
+       vc->vc_blink = 0;
+       vc->vc_color = vc->vc_def_color;
+}
+
+/* console_sem is held */
+static void csi_m(struct vc_data *vc)
+{
+       int i;
+
+       for (i = 0; i <= vc->vc_npar; i++)
+               switch (vc->vc_par[i]) {
+                       case 0: /* all attributes off */
+                               default_attr(vc);
+                               break;
+                       case 1:
+                               vc->vc_intensity = 2;
+                               break;
+                       case 2:
+                               vc->vc_intensity = 0;
+                               break;
+                       case 3:
+                               vc->vc_italic = 1;
+                               break;
+                       case 4:
+                               vc->vc_underline = 1;
+                               break;
+                       case 5:
+                               vc->vc_blink = 1;
+                               break;
+                       case 7:
+                               vc->vc_reverse = 1;
+                               break;
+                       case 10: /* ANSI X3.64-1979 (SCO-ish?)
+                                 * Select primary font, don't display
+                                 * control chars if defined, don't set
+                                 * bit 8 on output.
+                                 */
+                               vc->vc_translate = set_translate(vc->vc_charset == 0
+                                               ? vc->vc_G0_charset
+                                               : vc->vc_G1_charset, vc);
+                               vc->vc_disp_ctrl = 0;
+                               vc->vc_toggle_meta = 0;
+                               break;
+                       case 11: /* ANSI X3.64-1979 (SCO-ish?)
+                                 * Select first alternate font, lets
+                                 * chars < 32 be displayed as ROM chars.
+                                 */
+                               vc->vc_translate = set_translate(IBMPC_MAP, vc);
+                               vc->vc_disp_ctrl = 1;
+                               vc->vc_toggle_meta = 0;
+                               break;
+                       case 12: /* ANSI X3.64-1979 (SCO-ish?)
+                                 * Select second alternate font, toggle
+                                 * high bit before displaying as ROM char.
+                                 */
+                               vc->vc_translate = set_translate(IBMPC_MAP, vc);
+                               vc->vc_disp_ctrl = 1;
+                               vc->vc_toggle_meta = 1;
+                               break;
+                       case 21:
+                       case 22:
+                               vc->vc_intensity = 1;
+                               break;
+                       case 23:
+                               vc->vc_italic = 0;
+                               break;
+                       case 24:
+                               vc->vc_underline = 0;
+                               break;
+                       case 25:
+                               vc->vc_blink = 0;
+                               break;
+                       case 27:
+                               vc->vc_reverse = 0;
+                               break;
+                       case 38: /* ANSI X3.64-1979 (SCO-ish?)
+                                 * Enables underscore, white foreground
+                                 * with white underscore (Linux - use
+                                 * default foreground).
+                                 */
+                               vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
+                               vc->vc_underline = 1;
+                               break;
+                       case 39: /* ANSI X3.64-1979 (SCO-ish?)
+                                 * Disable underline option.
+                                 * Reset colour to default? It did this
+                                 * before...
+                                 */
+                               vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
+                               vc->vc_underline = 0;
+                               break;
+                       case 49:
+                               vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f);
+                               break;
+                       default:
+                               if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
+                                       vc->vc_color = color_table[vc->vc_par[i] - 30]
+                                               | (vc->vc_color & 0xf0);
+                               else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
+                                       vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
+                                               | (vc->vc_color & 0x0f);
+                               break;
+               }
+       update_attr(vc);
+}
+
+static void respond_string(const char *p, struct tty_struct *tty)
+{
+       while (*p) {
+               tty_insert_flip_char(tty, *p, 0);
+               p++;
+       }
+       con_schedule_flip(tty);
+}
+
+static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
+{
+       char buf[40];
+
+       sprintf(buf, "\033[%d;%dR", vc->vc_y + (vc->vc_decom ? vc->vc_top + 1 : 1), vc->vc_x + 1);
+       respond_string(buf, tty);
+}
+
+static inline void status_report(struct tty_struct *tty)
+{
+       respond_string("\033[0n", tty); /* Terminal ok */
+}
+
+static inline void respond_ID(struct tty_struct * tty)
+{
+       respond_string(VT102ID, tty);
+}
+
+void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry)
+{
+       char buf[8];
+
+       sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
+               (char)('!' + mry));
+       respond_string(buf, tty);
+}
+
+/* invoked via ioctl(TIOCLINUX) and through set_selection */
+int mouse_reporting(void)
+{
+       return vc_cons[fg_console].d->vc_report_mouse;
+}
+
+/* console_sem is held */
+static void set_mode(struct vc_data *vc, int on_off)
+{
+       int i;
+
+       for (i = 0; i <= vc->vc_npar; i++)
+               if (vc->vc_ques) {
+                       switch(vc->vc_par[i]) { /* DEC private modes set/reset */
+                       case 1:                 /* Cursor keys send ^[Ox/^[[x */
+                               if (on_off)
+                                       set_kbd(vc, decckm);
+                               else
+                                       clr_kbd(vc, decckm);
+                               break;
+                       case 3: /* 80/132 mode switch unimplemented */
+                               vc->vc_deccolm = on_off;
+#if 0
+                               vc_resize(deccolm ? 132 : 80, vc->vc_rows);
+                               /* this alone does not suffice; some user mode
+                                  utility has to change the hardware regs */
+#endif
+                               break;
+                       case 5:                 /* Inverted screen on/off */
+                               if (vc->vc_decscnm != on_off) {
+                                       vc->vc_decscnm = on_off;
+                                       invert_screen(vc, 0, vc->vc_screenbuf_size, 0);
+                                       update_attr(vc);
+                               }
+                               break;
+                       case 6:                 /* Origin relative/absolute */
+                               vc->vc_decom = on_off;
+                               gotoxay(vc, 0, 0);
+                               break;
+                       case 7:                 /* Autowrap on/off */
+                               vc->vc_decawm = on_off;
+                               break;
+                       case 8:                 /* Autorepeat on/off */
+                               if (on_off)
+                                       set_kbd(vc, decarm);
+                               else
+                                       clr_kbd(vc, decarm);
+                               break;
+                       case 9:
+                               vc->vc_report_mouse = on_off ? 1 : 0;
+                               break;
+                       case 25:                /* Cursor on/off */
+                               vc->vc_deccm = on_off;
+                               break;
+                       case 1000:
+                               vc->vc_report_mouse = on_off ? 2 : 0;
+                               break;
+                       }
+               } else {
+                       switch(vc->vc_par[i]) { /* ANSI modes set/reset */
+                       case 3:                 /* Monitor (display ctrls) */
+                               vc->vc_disp_ctrl = on_off;
+                               break;
+                       case 4:                 /* Insert Mode on/off */
+                               vc->vc_decim = on_off;
+                               break;
+                       case 20:                /* Lf, Enter == CrLf/Lf */
+                               if (on_off)
+                                       set_kbd(vc, lnm);
+                               else
+                                       clr_kbd(vc, lnm);
+                               break;
+                       }
+               }
+}
+
+/* console_sem is held */
+static void setterm_command(struct vc_data *vc)
+{
+       switch(vc->vc_par[0]) {
+               case 1: /* set color for underline mode */
+                       if (vc->vc_can_do_color &&
+                                       vc->vc_par[1] < 16) {
+                               vc->vc_ulcolor = color_table[vc->vc_par[1]];
+                               if (vc->vc_underline)
+                                       update_attr(vc);
+                       }
+                       break;
+               case 2: /* set color for half intensity mode */
+                       if (vc->vc_can_do_color &&
+                                       vc->vc_par[1] < 16) {
+                               vc->vc_halfcolor = color_table[vc->vc_par[1]];
+                               if (vc->vc_intensity == 0)
+                                       update_attr(vc);
+                       }
+                       break;
+               case 8: /* store colors as defaults */
+                       vc->vc_def_color = vc->vc_attr;
+                       if (vc->vc_hi_font_mask == 0x100)
+                               vc->vc_def_color >>= 1;
+                       default_attr(vc);
+                       update_attr(vc);
+                       break;
+               case 9: /* set blanking interval */
+                       blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60;
+                       poke_blanked_console();
+                       break;
+               case 10: /* set bell frequency in Hz */
+                       if (vc->vc_npar >= 1)
+                               vc->vc_bell_pitch = vc->vc_par[1];
+                       else
+                               vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
+                       break;
+               case 11: /* set bell duration in msec */
+                       if (vc->vc_npar >= 1)
+                               vc->vc_bell_duration = (vc->vc_par[1] < 2000) ?
+                                       vc->vc_par[1] * HZ / 1000 : 0;
+                       else
+                               vc->vc_bell_duration = DEFAULT_BELL_DURATION;
+                       break;
+               case 12: /* bring specified console to the front */
+                       if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1))
+                               set_console(vc->vc_par[1] - 1);
+                       break;
+               case 13: /* unblank the screen */
+                       poke_blanked_console();
+                       break;
+               case 14: /* set vesa powerdown interval */
+                       vesa_off_interval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ;
+                       break;
+               case 15: /* activate the previous console */
+                       set_console(last_console);
+                       break;
+       }
+}
+
+/* console_sem is held */
+static void csi_at(struct vc_data *vc, unsigned int nr)
+{
+       if (nr > vc->vc_cols - vc->vc_x)
+               nr = vc->vc_cols - vc->vc_x;
+       else if (!nr)
+               nr = 1;
+       insert_char(vc, nr);
+}
+
+/* console_sem is held */
+static void csi_L(struct vc_data *vc, unsigned int nr)
+{
+       if (nr > vc->vc_rows - vc->vc_y)
+               nr = vc->vc_rows - vc->vc_y;
+       else if (!nr)
+               nr = 1;
+       scrdown(vc, vc->vc_y, vc->vc_bottom, nr);
+       vc->vc_need_wrap = 0;
+}
+
+/* console_sem is held */
+static void csi_P(struct vc_data *vc, unsigned int nr)
+{
+       if (nr > vc->vc_cols - vc->vc_x)
+               nr = vc->vc_cols - vc->vc_x;
+       else if (!nr)
+               nr = 1;
+       delete_char(vc, nr);
+}
+
+/* console_sem is held */
+static void csi_M(struct vc_data *vc, unsigned int nr)
+{
+       if (nr > vc->vc_rows - vc->vc_y)
+               nr = vc->vc_rows - vc->vc_y;
+       else if (!nr)
+               nr=1;
+       scrup(vc, vc->vc_y, vc->vc_bottom, nr);
+       vc->vc_need_wrap = 0;
+}
+
+/* console_sem is held (except via vc_init->reset_terminal */
+static void save_cur(struct vc_data *vc)
+{
+       vc->vc_saved_x          = vc->vc_x;
+       vc->vc_saved_y          = vc->vc_y;
+       vc->vc_s_intensity      = vc->vc_intensity;
+       vc->vc_s_italic         = vc->vc_italic;
+       vc->vc_s_underline      = vc->vc_underline;
+       vc->vc_s_blink          = vc->vc_blink;
+       vc->vc_s_reverse        = vc->vc_reverse;
+       vc->vc_s_charset        = vc->vc_charset;
+       vc->vc_s_color          = vc->vc_color;
+       vc->vc_saved_G0         = vc->vc_G0_charset;
+       vc->vc_saved_G1         = vc->vc_G1_charset;
+}
+
+/* console_sem is held */
+static void restore_cur(struct vc_data *vc)
+{
+       gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y);
+       vc->vc_intensity        = vc->vc_s_intensity;
+       vc->vc_italic           = vc->vc_s_italic;
+       vc->vc_underline        = vc->vc_s_underline;
+       vc->vc_blink            = vc->vc_s_blink;
+       vc->vc_reverse          = vc->vc_s_reverse;
+       vc->vc_charset          = vc->vc_s_charset;
+       vc->vc_color            = vc->vc_s_color;
+       vc->vc_G0_charset       = vc->vc_saved_G0;
+       vc->vc_G1_charset       = vc->vc_saved_G1;
+       vc->vc_translate        = set_translate(vc->vc_charset ? vc->vc_G1_charset : vc->vc_G0_charset, vc);
+       update_attr(vc);
+       vc->vc_need_wrap = 0;
+}
+
+enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
+       EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
+       ESpalette };
+
+/* console_sem is held (except via vc_init()) */
+static void reset_terminal(struct vc_data *vc, int do_clear)
+{
+       vc->vc_top              = 0;
+       vc->vc_bottom           = vc->vc_rows;
+       vc->vc_state            = ESnormal;
+       vc->vc_ques             = 0;
+       vc->vc_translate        = set_translate(LAT1_MAP, vc);
+       vc->vc_G0_charset       = LAT1_MAP;
+       vc->vc_G1_charset       = GRAF_MAP;
+       vc->vc_charset          = 0;
+       vc->vc_need_wrap        = 0;
+       vc->vc_report_mouse     = 0;
+       vc->vc_utf              = default_utf8;
+       vc->vc_utf_count        = 0;
+
+       vc->vc_disp_ctrl        = 0;
+       vc->vc_toggle_meta      = 0;
+
+       vc->vc_decscnm          = 0;
+       vc->vc_decom            = 0;
+       vc->vc_decawm           = 1;
+       vc->vc_deccm            = global_cursor_default;
+       vc->vc_decim            = 0;
+
+       set_kbd(vc, decarm);
+       clr_kbd(vc, decckm);
+       clr_kbd(vc, kbdapplic);
+       clr_kbd(vc, lnm);
+       kbd_table[vc->vc_num].lockstate = 0;
+       kbd_table[vc->vc_num].slockstate = 0;
+       kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS;
+       kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate;
+       /* do not do set_leds here because this causes an endless tasklet loop
+          when the keyboard hasn't been initialized yet */
+
+       vc->vc_cursor_type = cur_default;
+       vc->vc_complement_mask = vc->vc_s_complement_mask;
+
+       default_attr(vc);
+       update_attr(vc);
+
+       vc->vc_tab_stop[0]      = 0x01010100;
+       vc->vc_tab_stop[1]      =
+       vc->vc_tab_stop[2]      =
+       vc->vc_tab_stop[3]      =
+       vc->vc_tab_stop[4]      =
+       vc->vc_tab_stop[5]      =
+       vc->vc_tab_stop[6]      =
+       vc->vc_tab_stop[7]      = 0x01010101;
+
+       vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
+       vc->vc_bell_duration = DEFAULT_BELL_DURATION;
+
+       gotoxy(vc, 0, 0);
+       save_cur(vc);
+       if (do_clear)
+           csi_J(vc, 2);
+}
+
+/* console_sem is held */
+static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
+{
+       /*
+        *  Control characters can be used in the _middle_
+        *  of an escape sequence.
+        */
+       switch (c) {
+       case 0:
+               return;
+       case 7:
+               if (vc->vc_bell_duration)
+                       kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
+               return;
+       case 8:
+               bs(vc);
+               return;
+       case 9:
+               vc->vc_pos -= (vc->vc_x << 1);
+               while (vc->vc_x < vc->vc_cols - 1) {
+                       vc->vc_x++;
+                       if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31)))
+                               break;
+               }
+               vc->vc_pos += (vc->vc_x << 1);
+               notify_write(vc, '\t');
+               return;
+       case 10: case 11: case 12:
+               lf(vc);
+               if (!is_kbd(vc, lnm))
+                       return;
+       case 13:
+               cr(vc);
+               return;
+       case 14:
+               vc->vc_charset = 1;
+               vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
+               vc->vc_disp_ctrl = 1;
+               return;
+       case 15:
+               vc->vc_charset = 0;
+               vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
+               vc->vc_disp_ctrl = 0;
+               return;
+       case 24: case 26:
+               vc->vc_state = ESnormal;
+               return;
+       case 27:
+               vc->vc_state = ESesc;
+               return;
+       case 127:
+               del(vc);
+               return;
+       case 128+27:
+               vc->vc_state = ESsquare;
+               return;
+       }
+       switch(vc->vc_state) {
+       case ESesc:
+               vc->vc_state = ESnormal;
+               switch (c) {
+               case '[':
+                       vc->vc_state = ESsquare;
+                       return;
+               case ']':
+                       vc->vc_state = ESnonstd;
+                       return;
+               case '%':
+                       vc->vc_state = ESpercent;
+                       return;
+               case 'E':
+                       cr(vc);
+                       lf(vc);
+                       return;
+               case 'M':
+                       ri(vc);
+                       return;
+               case 'D':
+                       lf(vc);
+                       return;
+               case 'H':
+                       vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31));
+                       return;
+               case 'Z':
+                       respond_ID(tty);
+                       return;
+               case '7':
+                       save_cur(vc);
+                       return;
+               case '8':
+                       restore_cur(vc);
+                       return;
+               case '(':
+                       vc->vc_state = ESsetG0;
+                       return;
+               case ')':
+                       vc->vc_state = ESsetG1;
+                       return;
+               case '#':
+                       vc->vc_state = EShash;
+                       return;
+               case 'c':
+                       reset_terminal(vc, 1);
+                       return;
+               case '>':  /* Numeric keypad */
+                       clr_kbd(vc, kbdapplic);
+                       return;
+               case '=':  /* Appl. keypad */
+                       set_kbd(vc, kbdapplic);
+                       return;
+               }
+               return;
+       case ESnonstd:
+               if (c=='P') {   /* palette escape sequence */
+                       for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
+                               vc->vc_par[vc->vc_npar] = 0;
+                       vc->vc_npar = 0;
+                       vc->vc_state = ESpalette;
+                       return;
+               } else if (c=='R') {   /* reset palette */
+                       reset_palette(vc);
+                       vc->vc_state = ESnormal;
+               } else
+                       vc->vc_state = ESnormal;
+               return;
+       case ESpalette:
+               if (isxdigit(c)) {
+                       vc->vc_par[vc->vc_npar++] = hex_to_bin(c);
+                       if (vc->vc_npar == 7) {
+                               int i = vc->vc_par[0] * 3, j = 1;
+                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
+                               vc->vc_palette[i++] += vc->vc_par[j++];
+                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
+                               vc->vc_palette[i++] += vc->vc_par[j++];
+                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
+                               vc->vc_palette[i] += vc->vc_par[j];
+                               set_palette(vc);
+                               vc->vc_state = ESnormal;
+                       }
+               } else
+                       vc->vc_state = ESnormal;
+               return;
+       case ESsquare:
+               for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
+                       vc->vc_par[vc->vc_npar] = 0;
+               vc->vc_npar = 0;
+               vc->vc_state = ESgetpars;
+               if (c == '[') { /* Function key */
+                       vc->vc_state=ESfunckey;
+                       return;
+               }
+               vc->vc_ques = (c == '?');
+               if (vc->vc_ques)
+                       return;
+       case ESgetpars:
+               if (c == ';' && vc->vc_npar < NPAR - 1) {
+                       vc->vc_npar++;
+                       return;
+               } else if (c>='0' && c<='9') {
+                       vc->vc_par[vc->vc_npar] *= 10;
+                       vc->vc_par[vc->vc_npar] += c - '0';
+                       return;
+               } else
+                       vc->vc_state = ESgotpars;
+       case ESgotpars:
+               vc->vc_state = ESnormal;
+               switch(c) {
+               case 'h':
+                       set_mode(vc, 1);
+                       return;
+               case 'l':
+                       set_mode(vc, 0);
+                       return;
+               case 'c':
+                       if (vc->vc_ques) {
+                               if (vc->vc_par[0])
+                                       vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16);
+                               else
+                                       vc->vc_cursor_type = cur_default;
+                               return;
+                       }
+                       break;
+               case 'm':
+                       if (vc->vc_ques) {
+                               clear_selection();
+                               if (vc->vc_par[0])
+                                       vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1];
+                               else
+                                       vc->vc_complement_mask = vc->vc_s_complement_mask;
+                               return;
+                       }
+                       break;
+               case 'n':
+                       if (!vc->vc_ques) {
+                               if (vc->vc_par[0] == 5)
+                                       status_report(tty);
+                               else if (vc->vc_par[0] == 6)
+                                       cursor_report(vc, tty);
+                       }
+                       return;
+               }
+               if (vc->vc_ques) {
+                       vc->vc_ques = 0;
+                       return;
+               }
+               switch(c) {
+               case 'G': case '`':
+                       if (vc->vc_par[0])
+                               vc->vc_par[0]--;
+                       gotoxy(vc, vc->vc_par[0], vc->vc_y);
+                       return;
+               case 'A':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, vc->vc_x, vc->vc_y - vc->vc_par[0]);
+                       return;
+               case 'B': case 'e':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, vc->vc_x, vc->vc_y + vc->vc_par[0]);
+                       return;
+               case 'C': case 'a':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, vc->vc_x + vc->vc_par[0], vc->vc_y);
+                       return;
+               case 'D':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, vc->vc_x - vc->vc_par[0], vc->vc_y);
+                       return;
+               case 'E':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, 0, vc->vc_y + vc->vc_par[0]);
+                       return;
+               case 'F':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, 0, vc->vc_y - vc->vc_par[0]);
+                       return;
+               case 'd':
+                       if (vc->vc_par[0])
+                               vc->vc_par[0]--;
+                       gotoxay(vc, vc->vc_x ,vc->vc_par[0]);
+                       return;
+               case 'H': case 'f':
+                       if (vc->vc_par[0])
+                               vc->vc_par[0]--;
+                       if (vc->vc_par[1])
+                               vc->vc_par[1]--;
+                       gotoxay(vc, vc->vc_par[1], vc->vc_par[0]);
+                       return;
+               case 'J':
+                       csi_J(vc, vc->vc_par[0]);
+                       return;
+               case 'K':
+                       csi_K(vc, vc->vc_par[0]);
+                       return;
+               case 'L':
+                       csi_L(vc, vc->vc_par[0]);
+                       return;
+               case 'M':
+                       csi_M(vc, vc->vc_par[0]);
+                       return;
+               case 'P':
+                       csi_P(vc, vc->vc_par[0]);
+                       return;
+               case 'c':
+                       if (!vc->vc_par[0])
+                               respond_ID(tty);
+                       return;
+               case 'g':
+                       if (!vc->vc_par[0])
+                               vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31));
+                       else if (vc->vc_par[0] == 3) {
+                               vc->vc_tab_stop[0] =
+                                       vc->vc_tab_stop[1] =
+                                       vc->vc_tab_stop[2] =
+                                       vc->vc_tab_stop[3] =
+                                       vc->vc_tab_stop[4] =
+                                       vc->vc_tab_stop[5] =
+                                       vc->vc_tab_stop[6] =
+                                       vc->vc_tab_stop[7] = 0;
+                       }
+                       return;
+               case 'm':
+                       csi_m(vc);
+                       return;
+               case 'q': /* DECLL - but only 3 leds */
+                       /* map 0,1,2,3 to 0,1,2,4 */
+                       if (vc->vc_par[0] < 4)
+                               setledstate(kbd_table + vc->vc_num,
+                                           (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
+                       return;
+               case 'r':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       if (!vc->vc_par[1])
+                               vc->vc_par[1] = vc->vc_rows;
+                       /* Minimum allowed region is 2 lines */
+                       if (vc->vc_par[0] < vc->vc_par[1] &&
+                           vc->vc_par[1] <= vc->vc_rows) {
+                               vc->vc_top = vc->vc_par[0] - 1;
+                               vc->vc_bottom = vc->vc_par[1];
+                               gotoxay(vc, 0, 0);
+                       }
+                       return;
+               case 's':
+                       save_cur(vc);
+                       return;
+               case 'u':
+                       restore_cur(vc);
+                       return;
+               case 'X':
+                       csi_X(vc, vc->vc_par[0]);
+                       return;
+               case '@':
+                       csi_at(vc, vc->vc_par[0]);
+                       return;
+               case ']': /* setterm functions */
+                       setterm_command(vc);
+                       return;
+               }
+               return;
+       case ESpercent:
+               vc->vc_state = ESnormal;
+               switch (c) {
+               case '@':  /* defined in ISO 2022 */
+                       vc->vc_utf = 0;
+                       return;
+               case 'G':  /* prelim official escape code */
+               case '8':  /* retained for compatibility */
+                       vc->vc_utf = 1;
+                       return;
+               }
+               return;
+       case ESfunckey:
+               vc->vc_state = ESnormal;
+               return;
+       case EShash:
+               vc->vc_state = ESnormal;
+               if (c == '8') {
+                       /* DEC screen alignment test. kludge :-) */
+                       vc->vc_video_erase_char =
+                               (vc->vc_video_erase_char & 0xff00) | 'E';
+                       csi_J(vc, 2);
+                       vc->vc_video_erase_char =
+                               (vc->vc_video_erase_char & 0xff00) | ' ';
+                       do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
+               }
+               return;
+       case ESsetG0:
+               if (c == '0')
+                       vc->vc_G0_charset = GRAF_MAP;
+               else if (c == 'B')
+                       vc->vc_G0_charset = LAT1_MAP;
+               else if (c == 'U')
+                       vc->vc_G0_charset = IBMPC_MAP;
+               else if (c == 'K')
+                       vc->vc_G0_charset = USER_MAP;
+               if (vc->vc_charset == 0)
+                       vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
+               vc->vc_state = ESnormal;
+               return;
+       case ESsetG1:
+               if (c == '0')
+                       vc->vc_G1_charset = GRAF_MAP;
+               else if (c == 'B')
+                       vc->vc_G1_charset = LAT1_MAP;
+               else if (c == 'U')
+                       vc->vc_G1_charset = IBMPC_MAP;
+               else if (c == 'K')
+                       vc->vc_G1_charset = USER_MAP;
+               if (vc->vc_charset == 1)
+                       vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
+               vc->vc_state = ESnormal;
+               return;
+       default:
+               vc->vc_state = ESnormal;
+       }
+}
+
+/* This is a temporary buffer used to prepare a tty console write
+ * so that we can easily avoid touching user space while holding the
+ * console spinlock.  It is allocated in con_init and is shared by
+ * this code and the vc_screen read/write tty calls.
+ *
+ * We have to allocate this statically in the kernel data section
+ * since console_init (and thus con_init) are called before any
+ * kernel memory allocation is available.
+ */
+char con_buf[CON_BUF_SIZE];
+DEFINE_MUTEX(con_buf_mtx);
+
+/* is_double_width() is based on the wcwidth() implementation by
+ * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
+ * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+ */
+struct interval {
+       uint32_t first;
+       uint32_t last;
+};
+
+static int bisearch(uint32_t ucs, const struct interval *table, int max)
+{
+       int min = 0;
+       int mid;
+
+       if (ucs < table[0].first || ucs > table[max].last)
+               return 0;
+       while (max >= min) {
+               mid = (min + max) / 2;
+               if (ucs > table[mid].last)
+                       min = mid + 1;
+               else if (ucs < table[mid].first)
+                       max = mid - 1;
+               else
+                       return 1;
+       }
+       return 0;
+}
+
+static int is_double_width(uint32_t ucs)
+{
+       static const struct interval double_width[] = {
+               { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E },
+               { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF },
+               { 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 },
+               { 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD }
+       };
+       return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1);
+}
+
+/* acquires console_sem */
+static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+#ifdef VT_BUF_VRAM_ONLY
+#define FLUSH do { } while(0);
+#else
+#define FLUSH if (draw_x >= 0) { \
+       vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \
+       draw_x = -1; \
+       }
+#endif
+
+       int c, tc, ok, n = 0, draw_x = -1;
+       unsigned int currcons;
+       unsigned long draw_from = 0, draw_to = 0;
+       struct vc_data *vc;
+       unsigned char vc_attr;
+       struct vt_notifier_param param;
+       uint8_t rescan;
+       uint8_t inverse;
+       uint8_t width;
+       u16 himask, charmask;
+
+       if (in_interrupt())
+               return count;
+
+       might_sleep();
+
+       acquire_console_sem();
+       vc = tty->driver_data;
+       if (vc == NULL) {
+               printk(KERN_ERR "vt: argh, driver_data is NULL !\n");
+               release_console_sem();
+               return 0;
+       }
+
+       currcons = vc->vc_num;
+       if (!vc_cons_allocated(currcons)) {
+           /* could this happen? */
+               printk_once("con_write: tty %d not allocated\n", currcons+1);
+           release_console_sem();
+           return 0;
+       }
+
+       himask = vc->vc_hi_font_mask;
+       charmask = himask ? 0x1ff : 0xff;
+
+       /* undraw cursor first */
+       if (IS_FG(vc))
+               hide_cursor(vc);
+
+       param.vc = vc;
+
+       while (!tty->stopped && count) {
+               int orig = *buf;
+               c = orig;
+               buf++;
+               n++;
+               count--;
+               rescan = 0;
+               inverse = 0;
+               width = 1;
+
+               /* Do no translation at all in control states */
+               if (vc->vc_state != ESnormal) {
+                       tc = c;
+               } else if (vc->vc_utf && !vc->vc_disp_ctrl) {
+                   /* Combine UTF-8 into Unicode in vc_utf_char.
+                    * vc_utf_count is the number of continuation bytes still
+                    * expected to arrive.
+                    * vc_npar is the number of continuation bytes arrived so
+                    * far
+                    */
+rescan_last_byte:
+                   if ((c & 0xc0) == 0x80) {
+                       /* Continuation byte received */
+                       static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff };
+                       if (vc->vc_utf_count) {
+                           vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
+                           vc->vc_npar++;
+                           if (--vc->vc_utf_count) {
+                               /* Still need some bytes */
+                               continue;
+                           }
+                           /* Got a whole character */
+                           c = vc->vc_utf_char;
+                           /* Reject overlong sequences */
+                           if (c <= utf8_length_changes[vc->vc_npar - 1] ||
+                                       c > utf8_length_changes[vc->vc_npar])
+                               c = 0xfffd;
+                       } else {
+                           /* Unexpected continuation byte */
+                           vc->vc_utf_count = 0;
+                           c = 0xfffd;
+                       }
+                   } else {
+                       /* Single ASCII byte or first byte of a sequence received */
+                       if (vc->vc_utf_count) {
+                           /* Continuation byte expected */
+                           rescan = 1;
+                           vc->vc_utf_count = 0;
+                           c = 0xfffd;
+                       } else if (c > 0x7f) {
+                           /* First byte of a multibyte sequence received */
+                           vc->vc_npar = 0;
+                           if ((c & 0xe0) == 0xc0) {
+                               vc->vc_utf_count = 1;
+                               vc->vc_utf_char = (c & 0x1f);
+                           } else if ((c & 0xf0) == 0xe0) {
+                               vc->vc_utf_count = 2;
+                               vc->vc_utf_char = (c & 0x0f);
+                           } else if ((c & 0xf8) == 0xf0) {
+                               vc->vc_utf_count = 3;
+                               vc->vc_utf_char = (c & 0x07);
+                           } else if ((c & 0xfc) == 0xf8) {
+                               vc->vc_utf_count = 4;
+                               vc->vc_utf_char = (c & 0x03);
+                           } else if ((c & 0xfe) == 0xfc) {
+                               vc->vc_utf_count = 5;
+                               vc->vc_utf_char = (c & 0x01);
+                           } else {
+                               /* 254 and 255 are invalid */
+                               c = 0xfffd;
+                           }
+                           if (vc->vc_utf_count) {
+                               /* Still need some bytes */
+                               continue;
+                           }
+                       }
+                       /* Nothing to do if an ASCII byte was received */
+                   }
+                   /* End of UTF-8 decoding. */
+                   /* c is the received character, or U+FFFD for invalid sequences. */
+                   /* Replace invalid Unicode code points with U+FFFD too */
+                   if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
+                       c = 0xfffd;
+                   tc = c;
+               } else {        /* no utf or alternate charset mode */
+                   tc = vc_translate(vc, c);
+               }
+
+               param.c = tc;
+               if (atomic_notifier_call_chain(&vt_notifier_list, VT_PREWRITE,
+                                       &param) == NOTIFY_STOP)
+                       continue;
+
+                /* If the original code was a control character we
+                 * only allow a glyph to be displayed if the code is
+                 * not normally used (such as for cursor movement) or
+                 * if the disp_ctrl mode has been explicitly enabled.
+                 * Certain characters (as given by the CTRL_ALWAYS
+                 * bitmap) are always displayed as control characters,
+                 * as the console would be pretty useless without
+                 * them; to display an arbitrary font position use the
+                 * direct-to-font zone in UTF-8 mode.
+                 */
+                ok = tc && (c >= 32 ||
+                           !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
+                                 vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
+                       && (c != 127 || vc->vc_disp_ctrl)
+                       && (c != 128+27);
+
+               if (vc->vc_state == ESnormal && ok) {
+                       if (vc->vc_utf && !vc->vc_disp_ctrl) {
+                               if (is_double_width(c))
+                                       width = 2;
+                       }
+                       /* Now try to find out how to display it */
+                       tc = conv_uni_to_pc(vc, tc);
+                       if (tc & ~charmask) {
+                               if (tc == -1 || tc == -2) {
+                                   continue; /* nothing to display */
+                               }
+                               /* Glyph not found */
+                               if ((!(vc->vc_utf && !vc->vc_disp_ctrl) || c < 128) && !(c & ~charmask)) {
+                                   /* In legacy mode use the glyph we get by a 1:1 mapping.
+                                      This would make absolutely no sense with Unicode in mind,
+                                      but do this for ASCII characters since a font may lack
+                                      Unicode mapping info and we don't want to end up with
+                                      having question marks only. */
+                                   tc = c;
+                               } else {
+                                   /* Display U+FFFD. If it's not found, display an inverse question mark. */
+                                   tc = conv_uni_to_pc(vc, 0xfffd);
+                                   if (tc < 0) {
+                                       inverse = 1;
+                                       tc = conv_uni_to_pc(vc, '?');
+                                       if (tc < 0) tc = '?';
+                                   }
+                               }
+                       }
+
+                       if (!inverse) {
+                               vc_attr = vc->vc_attr;
+                       } else {
+                               /* invert vc_attr */
+                               if (!vc->vc_can_do_color) {
+                                       vc_attr = (vc->vc_attr) ^ 0x08;
+                               } else if (vc->vc_hi_font_mask == 0x100) {
+                                       vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4);
+                               } else {
+                                       vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
+                               }
+                               FLUSH
+                       }
+
+                       while (1) {
+                               if (vc->vc_need_wrap || vc->vc_decim)
+                                       FLUSH
+                               if (vc->vc_need_wrap) {
+                                       cr(vc);
+                                       lf(vc);
+                               }
+                               if (vc->vc_decim)
+                                       insert_char(vc, 1);
+                               scr_writew(himask ?
+                                            ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
+                                            (vc_attr << 8) + tc,
+                                          (u16 *) vc->vc_pos);
+                               if (DO_UPDATE(vc) && draw_x < 0) {
+                                       draw_x = vc->vc_x;
+                                       draw_from = vc->vc_pos;
+                               }
+                               if (vc->vc_x == vc->vc_cols - 1) {
+                                       vc->vc_need_wrap = vc->vc_decawm;
+                                       draw_to = vc->vc_pos + 2;
+                               } else {
+                                       vc->vc_x++;
+                                       draw_to = (vc->vc_pos += 2);
+                               }
+
+                               if (!--width) break;
+
+                               tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
+                               if (tc < 0) tc = ' ';
+                       }
+                       notify_write(vc, c);
+
+                       if (inverse) {
+                               FLUSH
+                       }
+
+                       if (rescan) {
+                               rescan = 0;
+                               inverse = 0;
+                               width = 1;
+                               c = orig;
+                               goto rescan_last_byte;
+                       }
+                       continue;
+               }
+               FLUSH
+               do_con_trol(tty, vc, orig);
+       }
+       FLUSH
+       console_conditional_schedule();
+       release_console_sem();
+       notify_update(vc);
+       return n;
+#undef FLUSH
+}
+
+/*
+ * This is the console switching callback.
+ *
+ * Doing console switching in a process context allows
+ * us to do the switches asynchronously (needed when we want
+ * to switch due to a keyboard interrupt).  Synchronization
+ * with other console code and prevention of re-entrancy is
+ * ensured with console_sem.
+ */
+static void console_callback(struct work_struct *ignored)
+{
+       acquire_console_sem();
+
+       if (want_console >= 0) {
+               if (want_console != fg_console &&
+                   vc_cons_allocated(want_console)) {
+                       hide_cursor(vc_cons[fg_console].d);
+                       change_console(vc_cons[want_console].d);
+                       /* we only changed when the console had already
+                          been allocated - a new console is not created
+                          in an interrupt routine */
+               }
+               want_console = -1;
+       }
+       if (do_poke_blanked_console) { /* do not unblank for a LED change */
+               do_poke_blanked_console = 0;
+               poke_blanked_console();
+       }
+       if (scrollback_delta) {
+               struct vc_data *vc = vc_cons[fg_console].d;
+               clear_selection();
+               if (vc->vc_mode == KD_TEXT)
+                       vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
+               scrollback_delta = 0;
+       }
+       if (blank_timer_expired) {
+               do_blank_screen(0);
+               blank_timer_expired = 0;
+       }
+       notify_update(vc_cons[fg_console].d);
+
+       release_console_sem();
+}
+
+int set_console(int nr)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+
+       if (!vc_cons_allocated(nr) || vt_dont_switch ||
+               (vc->vt_mode.mode == VT_AUTO && vc->vc_mode == KD_GRAPHICS)) {
+
+               /*
+                * Console switch will fail in console_callback() or
+                * change_console() so there is no point scheduling
+                * the callback
+                *
+                * Existing set_console() users don't check the return
+                * value so this shouldn't break anything
+                */
+               return -EINVAL;
+       }
+
+       want_console = nr;
+       schedule_console_callback();
+
+       return 0;
+}
+
+struct tty_driver *console_driver;
+
+#ifdef CONFIG_VT_CONSOLE
+
+/**
+ * vt_kmsg_redirect() - Sets/gets the kernel message console
+ * @new:       The new virtual terminal number or -1 if the console should stay
+ *             unchanged
+ *
+ * By default, the kernel messages are always printed on the current virtual
+ * console. However, the user may modify that default with the
+ * TIOCL_SETKMSGREDIRECT ioctl call.
+ *
+ * This function sets the kernel message console to be @new. It returns the old
+ * virtual console number. The virtual terminal number 0 (both as parameter and
+ * return value) means no redirection (i.e. always printed on the currently
+ * active console).
+ *
+ * The parameter -1 means that only the current console is returned, but the
+ * value is not modified. You may use the macro vt_get_kmsg_redirect() in that
+ * case to make the code more understandable.
+ *
+ * When the kernel is compiled without CONFIG_VT_CONSOLE, this function ignores
+ * the parameter and always returns 0.
+ */
+int vt_kmsg_redirect(int new)
+{
+       static int kmsg_con;
+
+       if (new != -1)
+               return xchg(&kmsg_con, new);
+       else
+               return kmsg_con;
+}
+
+/*
+ *     Console on virtual terminal
+ *
+ * The console must be locked when we get here.
+ */
+
+static void vt_console_print(struct console *co, const char *b, unsigned count)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+       unsigned char c;
+       static DEFINE_SPINLOCK(printing_lock);
+       const ushort *start;
+       ushort cnt = 0;
+       ushort myx;
+       int kmsg_console;
+
+       /* console busy or not yet initialized */
+       if (!printable)
+               return;
+       if (!spin_trylock(&printing_lock))
+               return;
+
+       kmsg_console = vt_get_kmsg_redirect();
+       if (kmsg_console && vc_cons_allocated(kmsg_console - 1))
+               vc = vc_cons[kmsg_console - 1].d;
+
+       /* read `x' only after setting currcons properly (otherwise
+          the `x' macro will read the x of the foreground console). */
+       myx = vc->vc_x;
+
+       if (!vc_cons_allocated(fg_console)) {
+               /* impossible */
+               /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
+               goto quit;
+       }
+
+       if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc))
+               goto quit;
+
+       /* undraw cursor first */
+       if (IS_FG(vc))
+               hide_cursor(vc);
+
+       start = (ushort *)vc->vc_pos;
+
+       /* Contrived structure to try to emulate original need_wrap behaviour
+        * Problems caused when we have need_wrap set on '\n' character */
+       while (count--) {
+               c = *b++;
+               if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
+                       if (cnt > 0) {
+                               if (CON_IS_VISIBLE(vc))
+                                       vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
+                               vc->vc_x += cnt;
+                               if (vc->vc_need_wrap)
+                                       vc->vc_x--;
+                               cnt = 0;
+                       }
+                       if (c == 8) {           /* backspace */
+                               bs(vc);
+                               start = (ushort *)vc->vc_pos;
+                               myx = vc->vc_x;
+                               continue;
+                       }
+                       if (c != 13)
+                               lf(vc);
+                       cr(vc);
+                       start = (ushort *)vc->vc_pos;
+                       myx = vc->vc_x;
+                       if (c == 10 || c == 13)
+                               continue;
+               }
+               scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
+               notify_write(vc, c);
+               cnt++;
+               if (myx == vc->vc_cols - 1) {
+                       vc->vc_need_wrap = 1;
+                       continue;
+               }
+               vc->vc_pos += 2;
+               myx++;
+       }
+       if (cnt > 0) {
+               if (CON_IS_VISIBLE(vc))
+                       vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
+               vc->vc_x += cnt;
+               if (vc->vc_x == vc->vc_cols) {
+                       vc->vc_x--;
+                       vc->vc_need_wrap = 1;
+               }
+       }
+       set_cursor(vc);
+       notify_update(vc);
+
+quit:
+       spin_unlock(&printing_lock);
+}
+
+static struct tty_driver *vt_console_device(struct console *c, int *index)
+{
+       *index = c->index ? c->index-1 : fg_console;
+       return console_driver;
+}
+
+static struct console vt_console_driver = {
+       .name           = "tty",
+       .write          = vt_console_print,
+       .device         = vt_console_device,
+       .unblank        = unblank_screen,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+};
+#endif
+
+/*
+ *     Handling of Linux-specific VC ioctls
+ */
+
+/*
+ * Generally a bit racy with respect to console_sem().
+ *
+ * There are some functions which don't need it.
+ *
+ * There are some functions which can sleep for arbitrary periods
+ * (paste_selection) but we don't need the lock there anyway.
+ *
+ * set_selection has locking, and definitely needs it
+ */
+
+int tioclinux(struct tty_struct *tty, unsigned long arg)
+{
+       char type, data;
+       char __user *p = (char __user *)arg;
+       int lines;
+       int ret;
+
+       if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (get_user(type, p))
+               return -EFAULT;
+       ret = 0;
+
+       switch (type)
+       {
+               case TIOCL_SETSEL:
+                       acquire_console_sem();
+                       ret = set_selection((struct tiocl_selection __user *)(p+1), tty);
+                       release_console_sem();
+                       break;
+               case TIOCL_PASTESEL:
+                       ret = paste_selection(tty);
+                       break;
+               case TIOCL_UNBLANKSCREEN:
+                       acquire_console_sem();
+                       unblank_screen();
+                       release_console_sem();
+                       break;
+               case TIOCL_SELLOADLUT:
+                       ret = sel_loadlut(p);
+                       break;
+               case TIOCL_GETSHIFTSTATE:
+
+       /*
+        * Make it possible to react to Shift+Mousebutton.
+        * Note that 'shift_state' is an undocumented
+        * kernel-internal variable; programs not closely
+        * related to the kernel should not use this.
+        */
+                       data = shift_state;
+                       ret = __put_user(data, p);
+                       break;
+               case TIOCL_GETMOUSEREPORTING:
+                       data = mouse_reporting();
+                       ret = __put_user(data, p);
+                       break;
+               case TIOCL_SETVESABLANK:
+                       ret = set_vesa_blanking(p);
+                       break;
+               case TIOCL_GETKMSGREDIRECT:
+                       data = vt_get_kmsg_redirect();
+                       ret = __put_user(data, p);
+                       break;
+               case TIOCL_SETKMSGREDIRECT:
+                       if (!capable(CAP_SYS_ADMIN)) {
+                               ret = -EPERM;
+                       } else {
+                               if (get_user(data, p+1))
+                                       ret = -EFAULT;
+                               else
+                                       vt_kmsg_redirect(data);
+                       }
+                       break;
+               case TIOCL_GETFGCONSOLE:
+                       ret = fg_console;
+                       break;
+               case TIOCL_SCROLLCONSOLE:
+                       if (get_user(lines, (s32 __user *)(p+4))) {
+                               ret = -EFAULT;
+                       } else {
+                               scrollfront(vc_cons[fg_console].d, lines);
+                               ret = 0;
+                       }
+                       break;
+               case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
+                       acquire_console_sem();
+                       ignore_poke = 1;
+                       do_blank_screen(0);
+                       release_console_sem();
+                       break;
+               case TIOCL_BLANKEDSCREEN:
+                       ret = console_blanked;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+       }
+       return ret;
+}
+
+/*
+ * /dev/ttyN handling
+ */
+
+static int con_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+       int     retval;
+
+       retval = do_con_write(tty, buf, count);
+       con_flush_chars(tty);
+
+       return retval;
+}
+
+static int con_put_char(struct tty_struct *tty, unsigned char ch)
+{
+       if (in_interrupt())
+               return 0;       /* n_r3964 calls put_char() from interrupt context */
+       return do_con_write(tty, &ch, 1);
+}
+
+static int con_write_room(struct tty_struct *tty)
+{
+       if (tty->stopped)
+               return 0;
+       return 32768;           /* No limit, really; we're not buffering */
+}
+
+static int con_chars_in_buffer(struct tty_struct *tty)
+{
+       return 0;               /* we're not buffering */
+}
+
+/*
+ * con_throttle and con_unthrottle are only used for
+ * paste_selection(), which has to stuff in a large number of
+ * characters...
+ */
+static void con_throttle(struct tty_struct *tty)
+{
+}
+
+static void con_unthrottle(struct tty_struct *tty)
+{
+       struct vc_data *vc = tty->driver_data;
+
+       wake_up_interruptible(&vc->paste_wait);
+}
+
+/*
+ * Turn the Scroll-Lock LED on when the tty is stopped
+ */
+static void con_stop(struct tty_struct *tty)
+{
+       int console_num;
+       if (!tty)
+               return;
+       console_num = tty->index;
+       if (!vc_cons_allocated(console_num))
+               return;
+       set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
+       set_leds();
+}
+
+/*
+ * Turn the Scroll-Lock LED off when the console is started
+ */
+static void con_start(struct tty_struct *tty)
+{
+       int console_num;
+       if (!tty)
+               return;
+       console_num = tty->index;
+       if (!vc_cons_allocated(console_num))
+               return;
+       clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
+       set_leds();
+}
+
+static void con_flush_chars(struct tty_struct *tty)
+{
+       struct vc_data *vc;
+
+       if (in_interrupt())     /* from flush_to_ldisc */
+               return;
+
+       /* if we race with con_close(), vt may be null */
+       acquire_console_sem();
+       vc = tty->driver_data;
+       if (vc)
+               set_cursor(vc);
+       release_console_sem();
+}
+
+/*
+ * Allocate the console screen memory.
+ */
+static int con_open(struct tty_struct *tty, struct file *filp)
+{
+       unsigned int currcons = tty->index;
+       int ret = 0;
+
+       acquire_console_sem();
+       if (tty->driver_data == NULL) {
+               ret = vc_allocate(currcons);
+               if (ret == 0) {
+                       struct vc_data *vc = vc_cons[currcons].d;
+
+                       /* Still being freed */
+                       if (vc->port.tty) {
+                               release_console_sem();
+                               return -ERESTARTSYS;
+                       }
+                       tty->driver_data = vc;
+                       vc->port.tty = tty;
+
+                       if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
+                               tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
+                               tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
+                       }
+                       if (vc->vc_utf)
+                               tty->termios->c_iflag |= IUTF8;
+                       else
+                               tty->termios->c_iflag &= ~IUTF8;
+                       release_console_sem();
+                       return ret;
+               }
+       }
+       release_console_sem();
+       return ret;
+}
+
+static void con_close(struct tty_struct *tty, struct file *filp)
+{
+       /* Nothing to do - we defer to shutdown */
+}
+
+static void con_shutdown(struct tty_struct *tty)
+{
+       struct vc_data *vc = tty->driver_data;
+       BUG_ON(vc == NULL);
+       acquire_console_sem();
+       vc->port.tty = NULL;
+       release_console_sem();
+       tty_shutdown(tty);
+}
+
+static int default_italic_color    = 2; // green (ASCII)
+static int default_underline_color = 3; // cyan (ASCII)
+module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
+module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
+
+static void vc_init(struct vc_data *vc, unsigned int rows,
+                   unsigned int cols, int do_clear)
+{
+       int j, k ;
+
+       vc->vc_cols = cols;
+       vc->vc_rows = rows;
+       vc->vc_size_row = cols << 1;
+       vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
+
+       set_origin(vc);
+       vc->vc_pos = vc->vc_origin;
+       reset_vc(vc);
+       for (j=k=0; j<16; j++) {
+               vc->vc_palette[k++] = default_red[j] ;
+               vc->vc_palette[k++] = default_grn[j] ;
+               vc->vc_palette[k++] = default_blu[j] ;
+       }
+       vc->vc_def_color       = 0x07;   /* white */
+       vc->vc_ulcolor         = default_underline_color;
+       vc->vc_itcolor         = default_italic_color;
+       vc->vc_halfcolor       = 0x08;   /* grey */
+       init_waitqueue_head(&vc->paste_wait);
+       reset_terminal(vc, do_clear);
+}
+
+/*
+ * This routine initializes console interrupts, and does nothing
+ * else. If you want the screen to clear, call tty_write with
+ * the appropriate escape-sequence.
+ */
+
+static int __init con_init(void)
+{
+       const char *display_desc = NULL;
+       struct vc_data *vc;
+       unsigned int currcons = 0, i;
+
+       acquire_console_sem();
+
+       if (conswitchp)
+               display_desc = conswitchp->con_startup();
+       if (!display_desc) {
+               fg_console = 0;
+               release_console_sem();
+               return 0;
+       }
+
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               struct con_driver *con_driver = &registered_con_driver[i];
+
+               if (con_driver->con == NULL) {
+                       con_driver->con = conswitchp;
+                       con_driver->desc = display_desc;
+                       con_driver->flag = CON_DRIVER_FLAG_INIT;
+                       con_driver->first = 0;
+                       con_driver->last = MAX_NR_CONSOLES - 1;
+                       break;
+               }
+       }
+
+       for (i = 0; i < MAX_NR_CONSOLES; i++)
+               con_driver_map[i] = conswitchp;
+
+       if (blankinterval) {
+               blank_state = blank_normal_wait;
+               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
+       }
+
+       for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
+               vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
+               INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
+               tty_port_init(&vc->port);
+               visual_init(vc, currcons, 1);
+               vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
+               vc_init(vc, vc->vc_rows, vc->vc_cols,
+                       currcons || !vc->vc_sw->con_save_screen);
+       }
+       currcons = fg_console = 0;
+       master_display_fg = vc = vc_cons[currcons].d;
+       set_origin(vc);
+       save_screen(vc);
+       gotoxy(vc, vc->vc_x, vc->vc_y);
+       csi_J(vc, 0);
+       update_screen(vc);
+       printk("Console: %s %s %dx%d",
+               vc->vc_can_do_color ? "colour" : "mono",
+               display_desc, vc->vc_cols, vc->vc_rows);
+       printable = 1;
+       printk("\n");
+
+       release_console_sem();
+
+#ifdef CONFIG_VT_CONSOLE
+       register_console(&vt_console_driver);
+#endif
+       return 0;
+}
+console_initcall(con_init);
+
+static const struct tty_operations con_ops = {
+       .open = con_open,
+       .close = con_close,
+       .write = con_write,
+       .write_room = con_write_room,
+       .put_char = con_put_char,
+       .flush_chars = con_flush_chars,
+       .chars_in_buffer = con_chars_in_buffer,
+       .ioctl = vt_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = vt_compat_ioctl,
+#endif
+       .stop = con_stop,
+       .start = con_start,
+       .throttle = con_throttle,
+       .unthrottle = con_unthrottle,
+       .resize = vt_resize,
+       .shutdown = con_shutdown
+};
+
+static struct cdev vc0_cdev;
+
+int __init vty_init(const struct file_operations *console_fops)
+{
+       cdev_init(&vc0_cdev, console_fops);
+       if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
+           register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
+               panic("Couldn't register /dev/tty0 driver\n");
+       device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
+
+       vcs_init();
+
+       console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
+       if (!console_driver)
+               panic("Couldn't allocate console driver\n");
+       console_driver->owner = THIS_MODULE;
+       console_driver->name = "tty";
+       console_driver->name_base = 1;
+       console_driver->major = TTY_MAJOR;
+       console_driver->minor_start = 1;
+       console_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+       console_driver->init_termios = tty_std_termios;
+       if (default_utf8)
+               console_driver->init_termios.c_iflag |= IUTF8;
+       console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
+       tty_set_operations(console_driver, &con_ops);
+       if (tty_register_driver(console_driver))
+               panic("Couldn't register console driver\n");
+       kbd_init();
+       console_map_init();
+#ifdef CONFIG_MDA_CONSOLE
+       mda_console_init();
+#endif
+       return 0;
+}
+
+#ifndef VT_SINGLE_DRIVER
+
+static struct class *vtconsole_class;
+
+static int bind_con_driver(const struct consw *csw, int first, int last,
+                          int deflt)
+{
+       struct module *owner = csw->owner;
+       const char *desc = NULL;
+       struct con_driver *con_driver;
+       int i, j = -1, k = -1, retval = -ENODEV;
+
+       if (!try_module_get(owner))
+               return -ENODEV;
+
+       acquire_console_sem();
+
+       /* check if driver is registered */
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               con_driver = &registered_con_driver[i];
+
+               if (con_driver->con == csw) {
+                       desc = con_driver->desc;
+                       retval = 0;
+                       break;
+               }
+       }
+
+       if (retval)
+               goto err;
+
+       if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) {
+               csw->con_startup();
+               con_driver->flag |= CON_DRIVER_FLAG_INIT;
+       }
+
+       if (deflt) {
+               if (conswitchp)
+                       module_put(conswitchp->owner);
+
+               __module_get(owner);
+               conswitchp = csw;
+       }
+
+       first = max(first, con_driver->first);
+       last = min(last, con_driver->last);
+
+       for (i = first; i <= last; i++) {
+               int old_was_color;
+               struct vc_data *vc = vc_cons[i].d;
+
+               if (con_driver_map[i])
+                       module_put(con_driver_map[i]->owner);
+               __module_get(owner);
+               con_driver_map[i] = csw;
+
+               if (!vc || !vc->vc_sw)
+                       continue;
+
+               j = i;
+
+               if (CON_IS_VISIBLE(vc)) {
+                       k = i;
+                       save_screen(vc);
+               }
+
+               old_was_color = vc->vc_can_do_color;
+               vc->vc_sw->con_deinit(vc);
+               vc->vc_origin = (unsigned long)vc->vc_screenbuf;
+               visual_init(vc, i, 0);
+               set_origin(vc);
+               update_attr(vc);
+
+               /* If the console changed between mono <-> color, then
+                * the attributes in the screenbuf will be wrong.  The
+                * following resets all attributes to something sane.
+                */
+               if (old_was_color != vc->vc_can_do_color)
+                       clear_buffer_attributes(vc);
+       }
+
+       printk("Console: switching ");
+       if (!deflt)
+               printk("consoles %d-%d ", first+1, last+1);
+       if (j >= 0) {
+               struct vc_data *vc = vc_cons[j].d;
+
+               printk("to %s %s %dx%d\n",
+                      vc->vc_can_do_color ? "colour" : "mono",
+                      desc, vc->vc_cols, vc->vc_rows);
+
+               if (k >= 0) {
+                       vc = vc_cons[k].d;
+                       update_screen(vc);
+               }
+       } else
+               printk("to %s\n", desc);
+
+       retval = 0;
+err:
+       release_console_sem();
+       module_put(owner);
+       return retval;
+};
+
+#ifdef CONFIG_VT_HW_CONSOLE_BINDING
+static int con_is_graphics(const struct consw *csw, int first, int last)
+{
+       int i, retval = 0;
+
+       for (i = first; i <= last; i++) {
+               struct vc_data *vc = vc_cons[i].d;
+
+               if (vc && vc->vc_mode == KD_GRAPHICS) {
+                       retval = 1;
+                       break;
+               }
+       }
+
+       return retval;
+}
+
+/**
+ * unbind_con_driver - unbind a console driver
+ * @csw: pointer to console driver to unregister
+ * @first: first in range of consoles that @csw should be unbound from
+ * @last: last in range of consoles that @csw should be unbound from
+ * @deflt: should next bound console driver be default after @csw is unbound?
+ *
+ * To unbind a driver from all possible consoles, pass 0 as @first and
+ * %MAX_NR_CONSOLES as @last.
+ *
+ * @deflt controls whether the console that ends up replacing @csw should be
+ * the default console.
+ *
+ * RETURNS:
+ * -ENODEV if @csw isn't a registered console driver or can't be unregistered
+ * or 0 on success.
+ */
+int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
+{
+       struct module *owner = csw->owner;
+       const struct consw *defcsw = NULL;
+       struct con_driver *con_driver = NULL, *con_back = NULL;
+       int i, retval = -ENODEV;
+
+       if (!try_module_get(owner))
+               return -ENODEV;
+
+       acquire_console_sem();
+
+       /* check if driver is registered and if it is unbindable */
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               con_driver = &registered_con_driver[i];
+
+               if (con_driver->con == csw &&
+                   con_driver->flag & CON_DRIVER_FLAG_MODULE) {
+                       retval = 0;
+                       break;
+               }
+       }
+
+       if (retval) {
+               release_console_sem();
+               goto err;
+       }
+
+       retval = -ENODEV;
+
+       /* check if backup driver exists */
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               con_back = &registered_con_driver[i];
+
+               if (con_back->con &&
+                   !(con_back->flag & CON_DRIVER_FLAG_MODULE)) {
+                       defcsw = con_back->con;
+                       retval = 0;
+                       break;
+               }
+       }
+
+       if (retval) {
+               release_console_sem();
+               goto err;
+       }
+
+       if (!con_is_bound(csw)) {
+               release_console_sem();
+               goto err;
+       }
+
+       first = max(first, con_driver->first);
+       last = min(last, con_driver->last);
+
+       for (i = first; i <= last; i++) {
+               if (con_driver_map[i] == csw) {
+                       module_put(csw->owner);
+                       con_driver_map[i] = NULL;
+               }
+       }
+
+       if (!con_is_bound(defcsw)) {
+               const struct consw *defconsw = conswitchp;
+
+               defcsw->con_startup();
+               con_back->flag |= CON_DRIVER_FLAG_INIT;
+               /*
+                * vgacon may change the default driver to point
+                * to dummycon, we restore it here...
+                */
+               conswitchp = defconsw;
+       }
+
+       if (!con_is_bound(csw))
+               con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
+
+       release_console_sem();
+       /* ignore return value, binding should not fail */
+       bind_con_driver(defcsw, first, last, deflt);
+err:
+       module_put(owner);
+       return retval;
+
+}
+EXPORT_SYMBOL(unbind_con_driver);
+
+static int vt_bind(struct con_driver *con)
+{
+       const struct consw *defcsw = NULL, *csw = NULL;
+       int i, more = 1, first = -1, last = -1, deflt = 0;
+
+       if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
+           con_is_graphics(con->con, con->first, con->last))
+               goto err;
+
+       csw = con->con;
+
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               struct con_driver *con = &registered_con_driver[i];
+
+               if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) {
+                       defcsw = con->con;
+                       break;
+               }
+       }
+
+       if (!defcsw)
+               goto err;
+
+       while (more) {
+               more = 0;
+
+               for (i = con->first; i <= con->last; i++) {
+                       if (con_driver_map[i] == defcsw) {
+                               if (first == -1)
+                                       first = i;
+                               last = i;
+                               more = 1;
+                       } else if (first != -1)
+                               break;
+               }
+
+               if (first == 0 && last == MAX_NR_CONSOLES -1)
+                       deflt = 1;
+
+               if (first != -1)
+                       bind_con_driver(csw, first, last, deflt);
+
+               first = -1;
+               last = -1;
+               deflt = 0;
+       }
+
+err:
+       return 0;
+}
+
+static int vt_unbind(struct con_driver *con)
+{
+       const struct consw *csw = NULL;
+       int i, more = 1, first = -1, last = -1, deflt = 0;
+
+       if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
+           con_is_graphics(con->con, con->first, con->last))
+               goto err;
+
+       csw = con->con;
+
+       while (more) {
+               more = 0;
+
+               for (i = con->first; i <= con->last; i++) {
+                       if (con_driver_map[i] == csw) {
+                               if (first == -1)
+                                       first = i;
+                               last = i;
+                               more = 1;
+                       } else if (first != -1)
+                               break;
+               }
+
+               if (first == 0 && last == MAX_NR_CONSOLES -1)
+                       deflt = 1;
+
+               if (first != -1)
+                       unbind_con_driver(csw, first, last, deflt);
+
+               first = -1;
+               last = -1;
+               deflt = 0;
+       }
+
+err:
+       return 0;
+}
+#else
+static inline int vt_bind(struct con_driver *con)
+{
+       return 0;
+}
+static inline int vt_unbind(struct con_driver *con)
+{
+       return 0;
+}
+#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
+
+static ssize_t store_bind(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct con_driver *con = dev_get_drvdata(dev);
+       int bind = simple_strtoul(buf, NULL, 0);
+
+       if (bind)
+               vt_bind(con);
+       else
+               vt_unbind(con);
+
+       return count;
+}
+
+static ssize_t show_bind(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct con_driver *con = dev_get_drvdata(dev);
+       int bind = con_is_bound(con->con);
+
+       return snprintf(buf, PAGE_SIZE, "%i\n", bind);
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct con_driver *con = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%s %s\n",
+                       (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
+                        con->desc);
+
+}
+
+static struct device_attribute device_attrs[] = {
+       __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind),
+       __ATTR(name, S_IRUGO, show_name, NULL),
+};
+
+static int vtconsole_init_device(struct con_driver *con)
+{
+       int i;
+       int error = 0;
+
+       con->flag |= CON_DRIVER_FLAG_ATTR;
+       dev_set_drvdata(con->dev, con);
+       for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
+               error = device_create_file(con->dev, &device_attrs[i]);
+               if (error)
+                       break;
+       }
+
+       if (error) {
+               while (--i >= 0)
+                       device_remove_file(con->dev, &device_attrs[i]);
+               con->flag &= ~CON_DRIVER_FLAG_ATTR;
+       }
+
+       return error;
+}
+
+static void vtconsole_deinit_device(struct con_driver *con)
+{
+       int i;
+
+       if (con->flag & CON_DRIVER_FLAG_ATTR) {
+               for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
+                       device_remove_file(con->dev, &device_attrs[i]);
+               con->flag &= ~CON_DRIVER_FLAG_ATTR;
+       }
+}
+
+/**
+ * con_is_bound - checks if driver is bound to the console
+ * @csw: console driver
+ *
+ * RETURNS: zero if unbound, nonzero if bound
+ *
+ * Drivers can call this and if zero, they should release
+ * all resources allocated on con_startup()
+ */
+int con_is_bound(const struct consw *csw)
+{
+       int i, bound = 0;
+
+       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               if (con_driver_map[i] == csw) {
+                       bound = 1;
+                       break;
+               }
+       }
+
+       return bound;
+}
+EXPORT_SYMBOL(con_is_bound);
+
+/**
+ * con_debug_enter - prepare the console for the kernel debugger
+ * @sw: console driver
+ *
+ * Called when the console is taken over by the kernel debugger, this
+ * function needs to save the current console state, then put the console
+ * into a state suitable for the kernel debugger.
+ *
+ * RETURNS:
+ * Zero on success, nonzero if a failure occurred when trying to prepare
+ * the console for the debugger.
+ */
+int con_debug_enter(struct vc_data *vc)
+{
+       int ret = 0;
+
+       saved_fg_console = fg_console;
+       saved_last_console = last_console;
+       saved_want_console = want_console;
+       saved_vc_mode = vc->vc_mode;
+       saved_console_blanked = console_blanked;
+       vc->vc_mode = KD_TEXT;
+       console_blanked = 0;
+       if (vc->vc_sw->con_debug_enter)
+               ret = vc->vc_sw->con_debug_enter(vc);
+#ifdef CONFIG_KGDB_KDB
+       /* Set the initial LINES variable if it is not already set */
+       if (vc->vc_rows < 999) {
+               int linecount;
+               char lns[4];
+               const char *setargs[3] = {
+                       "set",
+                       "LINES",
+                       lns,
+               };
+               if (kdbgetintenv(setargs[0], &linecount)) {
+                       snprintf(lns, 4, "%i", vc->vc_rows);
+                       kdb_set(2, setargs);
+               }
+       }
+#endif /* CONFIG_KGDB_KDB */
+       return ret;
+}
+EXPORT_SYMBOL_GPL(con_debug_enter);
+
+/**
+ * con_debug_leave - restore console state
+ * @sw: console driver
+ *
+ * Restore the console state to what it was before the kernel debugger
+ * was invoked.
+ *
+ * RETURNS:
+ * Zero on success, nonzero if a failure occurred when trying to restore
+ * the console.
+ */
+int con_debug_leave(void)
+{
+       struct vc_data *vc;
+       int ret = 0;
+
+       fg_console = saved_fg_console;
+       last_console = saved_last_console;
+       want_console = saved_want_console;
+       console_blanked = saved_console_blanked;
+       vc_cons[fg_console].d->vc_mode = saved_vc_mode;
+
+       vc = vc_cons[fg_console].d;
+       if (vc->vc_sw->con_debug_leave)
+               ret = vc->vc_sw->con_debug_leave(vc);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(con_debug_leave);
+
+/**
+ * register_con_driver - register console driver to console layer
+ * @csw: console driver
+ * @first: the first console to take over, minimum value is 0
+ * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
+ *
+ * DESCRIPTION: This function registers a console driver which can later
+ * bind to a range of consoles specified by @first and @last. It will
+ * also initialize the console driver by calling con_startup().
+ */
+int register_con_driver(const struct consw *csw, int first, int last)
+{
+       struct module *owner = csw->owner;
+       struct con_driver *con_driver;
+       const char *desc;
+       int i, retval = 0;
+
+       if (!try_module_get(owner))
+               return -ENODEV;
+
+       acquire_console_sem();
+
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               con_driver = &registered_con_driver[i];
+
+               /* already registered */
+               if (con_driver->con == csw)
+                       retval = -EINVAL;
+       }
+
+       if (retval)
+               goto err;
+
+       desc = csw->con_startup();
+
+       if (!desc)
+               goto err;
+
+       retval = -EINVAL;
+
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               con_driver = &registered_con_driver[i];
+
+               if (con_driver->con == NULL) {
+                       con_driver->con = csw;
+                       con_driver->desc = desc;
+                       con_driver->node = i;
+                       con_driver->flag = CON_DRIVER_FLAG_MODULE |
+                                          CON_DRIVER_FLAG_INIT;
+                       con_driver->first = first;
+                       con_driver->last = last;
+                       retval = 0;
+                       break;
+               }
+       }
+
+       if (retval)
+               goto err;
+
+       con_driver->dev = device_create(vtconsole_class, NULL,
+                                               MKDEV(0, con_driver->node),
+                                               NULL, "vtcon%i",
+                                               con_driver->node);
+
+       if (IS_ERR(con_driver->dev)) {
+               printk(KERN_WARNING "Unable to create device for %s; "
+                      "errno = %ld\n", con_driver->desc,
+                      PTR_ERR(con_driver->dev));
+               con_driver->dev = NULL;
+       } else {
+               vtconsole_init_device(con_driver);
+       }
+
+err:
+       release_console_sem();
+       module_put(owner);
+       return retval;
+}
+EXPORT_SYMBOL(register_con_driver);
+
+/**
+ * unregister_con_driver - unregister console driver from console layer
+ * @csw: console driver
+ *
+ * DESCRIPTION: All drivers that registers to the console layer must
+ * call this function upon exit, or if the console driver is in a state
+ * where it won't be able to handle console services, such as the
+ * framebuffer console without loaded framebuffer drivers.
+ *
+ * The driver must unbind first prior to unregistration.
+ */
+int unregister_con_driver(const struct consw *csw)
+{
+       int i, retval = -ENODEV;
+
+       acquire_console_sem();
+
+       /* cannot unregister a bound driver */
+       if (con_is_bound(csw))
+               goto err;
+
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               struct con_driver *con_driver = &registered_con_driver[i];
+
+               if (con_driver->con == csw &&
+                   con_driver->flag & CON_DRIVER_FLAG_MODULE) {
+                       vtconsole_deinit_device(con_driver);
+                       device_destroy(vtconsole_class,
+                                      MKDEV(0, con_driver->node));
+                       con_driver->con = NULL;
+                       con_driver->desc = NULL;
+                       con_driver->dev = NULL;
+                       con_driver->node = 0;
+                       con_driver->flag = 0;
+                       con_driver->first = 0;
+                       con_driver->last = 0;
+                       retval = 0;
+                       break;
+               }
+       }
+err:
+       release_console_sem();
+       return retval;
+}
+EXPORT_SYMBOL(unregister_con_driver);
+
+/*
+ *     If we support more console drivers, this function is used
+ *     when a driver wants to take over some existing consoles
+ *     and become default driver for newly opened ones.
+ *
+ *      take_over_console is basically a register followed by unbind
+ */
+int take_over_console(const struct consw *csw, int first, int last, int deflt)
+{
+       int err;
+
+       err = register_con_driver(csw, first, last);
+
+       if (!err)
+               bind_con_driver(csw, first, last, deflt);
+
+       return err;
+}
+
+/*
+ * give_up_console is a wrapper to unregister_con_driver. It will only
+ * work if driver is fully unbound.
+ */
+void give_up_console(const struct consw *csw)
+{
+       unregister_con_driver(csw);
+}
+
+static int __init vtconsole_class_init(void)
+{
+       int i;
+
+       vtconsole_class = class_create(THIS_MODULE, "vtconsole");
+       if (IS_ERR(vtconsole_class)) {
+               printk(KERN_WARNING "Unable to create vt console class; "
+                      "errno = %ld\n", PTR_ERR(vtconsole_class));
+               vtconsole_class = NULL;
+       }
+
+       /* Add system drivers to sysfs */
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               struct con_driver *con = &registered_con_driver[i];
+
+               if (con->con && !con->dev) {
+                       con->dev = device_create(vtconsole_class, NULL,
+                                                        MKDEV(0, con->node),
+                                                        NULL, "vtcon%i",
+                                                        con->node);
+
+                       if (IS_ERR(con->dev)) {
+                               printk(KERN_WARNING "Unable to create "
+                                      "device for %s; errno = %ld\n",
+                                      con->desc, PTR_ERR(con->dev));
+                               con->dev = NULL;
+                       } else {
+                               vtconsole_init_device(con);
+                       }
+               }
+       }
+
+       return 0;
+}
+postcore_initcall(vtconsole_class_init);
+
+#endif
+
+/*
+ *     Screen blanking
+ */
+
+static int set_vesa_blanking(char __user *p)
+{
+       unsigned int mode;
+
+       if (get_user(mode, p + 1))
+               return -EFAULT;
+
+       vesa_blank_mode = (mode < 4) ? mode : 0;
+       return 0;
+}
+
+void do_blank_screen(int entering_gfx)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+       int i;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       if (console_blanked) {
+               if (blank_state == blank_vesa_wait) {
+                       blank_state = blank_off;
+                       vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0);
+               }
+               return;
+       }
+
+       /* entering graphics mode? */
+       if (entering_gfx) {
+               hide_cursor(vc);
+               save_screen(vc);
+               vc->vc_sw->con_blank(vc, -1, 1);
+               console_blanked = fg_console + 1;
+               blank_state = blank_off;
+               set_origin(vc);
+               return;
+       }
+
+       if (blank_state != blank_normal_wait)
+               return;
+       blank_state = blank_off;
+
+       /* don't blank graphics */
+       if (vc->vc_mode != KD_TEXT) {
+               console_blanked = fg_console + 1;
+               return;
+       }
+
+       hide_cursor(vc);
+       del_timer_sync(&console_timer);
+       blank_timer_expired = 0;
+
+       save_screen(vc);
+       /* In case we need to reset origin, blanking hook returns 1 */
+       i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0);
+       console_blanked = fg_console + 1;
+       if (i)
+               set_origin(vc);
+
+       if (console_blank_hook && console_blank_hook(1))
+               return;
+
+       if (vesa_off_interval && vesa_blank_mode) {
+               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);
+
+/*
+ * Called by timer as well as from vt_console_driver
+ */
+void do_unblank_screen(int leaving_gfx)
+{
+       struct vc_data *vc;
+
+       /* This should now always be called from a "sane" (read: can schedule)
+        * context for the sake of the low level drivers, except in the special
+        * case of oops_in_progress
+        */
+       if (!oops_in_progress)
+               might_sleep();
+
+       WARN_CONSOLE_UNLOCKED();
+
+       ignore_poke = 0;
+       if (!console_blanked)
+               return;
+       if (!vc_cons_allocated(fg_console)) {
+               /* impossible */
+               printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
+               return;
+       }
+       vc = vc_cons[fg_console].d;
+       /* Try to unblank in oops case too */
+       if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc))
+               return; /* but leave console_blanked != 0 */
+
+       if (blankinterval) {
+               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
+               blank_state = blank_normal_wait;
+       }
+
+       console_blanked = 0;
+       if (vc->vc_sw->con_blank(vc, 0, leaving_gfx) || vt_force_oops_output(vc))
+               /* Low-level driver cannot restore -> do it ourselves */
+               update_screen(vc);
+       if (console_blank_hook)
+               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);
+
+/*
+ * This is called by the outside world to cause a forced unblank, mostly for
+ * oopses. Currently, I just call do_unblank_screen(0), but we could eventually
+ * call it with 1 as an argument and so force a mode restore... that may kill
+ * X or at least garbage the screen but would also make the Oops visible...
+ */
+void unblank_screen(void)
+{
+       do_unblank_screen(0);
+}
+
+/*
+ * We defer the timer blanking to work queue so it can take the console mutex
+ * (console operations can still happen at irq time, but only from printk which
+ * has the console mutex. Not perfect yet, but better than no locking
+ */
+static void blank_screen_t(unsigned long dummy)
+{
+       if (unlikely(!keventd_up())) {
+               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
+               return;
+       }
+       blank_timer_expired = 1;
+       schedule_work(&console_work);
+}
+
+void poke_blanked_console(void)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       /* Add this so we quickly catch whoever might call us in a non
+        * safe context. Nowadays, unblank_screen() isn't to be called in
+        * atomic contexts and is allowed to schedule (with the special case
+        * of oops_in_progress, but that isn't of any concern for this
+        * function. --BenH.
+        */
+       might_sleep();
+
+       /* This isn't perfectly race free, but a race here would be mostly harmless,
+        * at worse, we'll do a spurrious blank and it's unlikely
+        */
+       del_timer(&console_timer);
+       blank_timer_expired = 0;
+
+       if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS)
+               return;
+       if (console_blanked)
+               unblank_screen();
+       else if (blankinterval) {
+               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
+               blank_state = blank_normal_wait;
+       }
+}
+
+/*
+ *     Palettes
+ */
+
+static void set_palette(struct vc_data *vc)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (vc->vc_mode != KD_GRAPHICS)
+               vc->vc_sw->con_set_palette(vc, color_table);
+}
+
+static int set_get_cmap(unsigned char __user *arg, int set)
+{
+    int i, j, k;
+
+    WARN_CONSOLE_UNLOCKED();
+
+    for (i = 0; i < 16; i++)
+       if (set) {
+           get_user(default_red[i], arg++);
+           get_user(default_grn[i], arg++);
+           get_user(default_blu[i], arg++);
+       } else {
+           put_user(default_red[i], arg++);
+           put_user(default_grn[i], arg++);
+           put_user(default_blu[i], arg++);
+       }
+    if (set) {
+       for (i = 0; i < MAX_NR_CONSOLES; i++)
+           if (vc_cons_allocated(i)) {
+               for (j = k = 0; j < 16; j++) {
+                   vc_cons[i].d->vc_palette[k++] = default_red[j];
+                   vc_cons[i].d->vc_palette[k++] = default_grn[j];
+                   vc_cons[i].d->vc_palette[k++] = default_blu[j];
+               }
+               set_palette(vc_cons[i].d);
+           }
+    }
+    return 0;
+}
+
+/*
+ * Load palette into the DAC registers. arg points to a colour
+ * map, 3 bytes per colour, 16 colours, range from 0 to 255.
+ */
+
+int con_set_cmap(unsigned char __user *arg)
+{
+       int rc;
+
+       acquire_console_sem();
+       rc = set_get_cmap (arg,1);
+       release_console_sem();
+
+       return rc;
+}
+
+int con_get_cmap(unsigned char __user *arg)
+{
+       int rc;
+
+       acquire_console_sem();
+       rc = set_get_cmap (arg,0);
+       release_console_sem();
+
+       return rc;
+}
+
+void reset_palette(struct vc_data *vc)
+{
+       int j, k;
+       for (j=k=0; j<16; j++) {
+               vc->vc_palette[k++] = default_red[j];
+               vc->vc_palette[k++] = default_grn[j];
+               vc->vc_palette[k++] = default_blu[j];
+       }
+       set_palette(vc);
+}
+
+/*
+ *  Font switching
+ *
+ *  Currently we only support fonts up to 32 pixels wide, at a maximum height
+ *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, 
+ *  depending on width) reserved for each character which is kinda wasty, but 
+ *  this is done in order to maintain compatibility with the EGA/VGA fonts. It 
+ *  is upto the actual low-level console-driver convert data into its favorite
+ *  format (maybe we should add a `fontoffset' field to the `display'
+ *  structure so we won't have to convert the fontdata all the time.
+ *  /Jes
+ */
+
+#define max_font_size 65536
+
+static int con_font_get(struct vc_data *vc, struct console_font_op *op)
+{
+       struct console_font font;
+       int rc = -EINVAL;
+       int c;
+
+       if (vc->vc_mode != KD_TEXT)
+               return -EINVAL;
+
+       if (op->data) {
+               font.data = kmalloc(max_font_size, GFP_KERNEL);
+               if (!font.data)
+                       return -ENOMEM;
+       } else
+               font.data = NULL;
+
+       acquire_console_sem();
+       if (vc->vc_sw->con_font_get)
+               rc = vc->vc_sw->con_font_get(vc, &font);
+       else
+               rc = -ENOSYS;
+       release_console_sem();
+
+       if (rc)
+               goto out;
+
+       c = (font.width+7)/8 * 32 * font.charcount;
+
+       if (op->data && font.charcount > op->charcount)
+               rc = -ENOSPC;
+       if (!(op->flags & KD_FONT_FLAG_OLD)) {
+               if (font.width > op->width || font.height > op->height) 
+                       rc = -ENOSPC;
+       } else {
+               if (font.width != 8)
+                       rc = -EIO;
+               else if ((op->height && font.height > op->height) ||
+                        font.height > 32)
+                       rc = -ENOSPC;
+       }
+       if (rc)
+               goto out;
+
+       op->height = font.height;
+       op->width = font.width;
+       op->charcount = font.charcount;
+
+       if (op->data && copy_to_user(op->data, font.data, c))
+               rc = -EFAULT;
+
+out:
+       kfree(font.data);
+       return rc;
+}
+
+static int con_font_set(struct vc_data *vc, struct console_font_op *op)
+{
+       struct console_font font;
+       int rc = -EINVAL;
+       int size;
+
+       if (vc->vc_mode != KD_TEXT)
+               return -EINVAL;
+       if (!op->data)
+               return -EINVAL;
+       if (op->charcount > 512)
+               return -EINVAL;
+       if (!op->height) {              /* Need to guess font height [compat] */
+               int h, i;
+               u8 __user *charmap = op->data;
+               u8 tmp;
+               
+               /* If from KDFONTOP ioctl, don't allow things which can be done in userland,
+                  so that we can get rid of this soon */
+               if (!(op->flags & KD_FONT_FLAG_OLD))
+                       return -EINVAL;
+               for (h = 32; h > 0; h--)
+                       for (i = 0; i < op->charcount; i++) {
+                               if (get_user(tmp, &charmap[32*i+h-1]))
+                                       return -EFAULT;
+                               if (tmp)
+                                       goto nonzero;
+                       }
+               return -EINVAL;
+       nonzero:
+               op->height = h;
+       }
+       if (op->width <= 0 || op->width > 32 || op->height > 32)
+               return -EINVAL;
+       size = (op->width+7)/8 * 32 * op->charcount;
+       if (size > max_font_size)
+               return -ENOSPC;
+       font.charcount = op->charcount;
+       font.height = op->height;
+       font.width = op->width;
+       font.data = memdup_user(op->data, size);
+       if (IS_ERR(font.data))
+               return PTR_ERR(font.data);
+       acquire_console_sem();
+       if (vc->vc_sw->con_font_set)
+               rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
+       else
+               rc = -ENOSYS;
+       release_console_sem();
+       kfree(font.data);
+       return rc;
+}
+
+static int con_font_default(struct vc_data *vc, struct console_font_op *op)
+{
+       struct console_font font = {.width = op->width, .height = op->height};
+       char name[MAX_FONT_NAME];
+       char *s = name;
+       int rc;
+
+       if (vc->vc_mode != KD_TEXT)
+               return -EINVAL;
+
+       if (!op->data)
+               s = NULL;
+       else if (strncpy_from_user(name, op->data, MAX_FONT_NAME - 1) < 0)
+               return -EFAULT;
+       else
+               name[MAX_FONT_NAME - 1] = 0;
+
+       acquire_console_sem();
+       if (vc->vc_sw->con_font_default)
+               rc = vc->vc_sw->con_font_default(vc, &font, s);
+       else
+               rc = -ENOSYS;
+       release_console_sem();
+       if (!rc) {
+               op->width = font.width;
+               op->height = font.height;
+       }
+       return rc;
+}
+
+static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
+{
+       int con = op->height;
+       int rc;
+
+       if (vc->vc_mode != KD_TEXT)
+               return -EINVAL;
+
+       acquire_console_sem();
+       if (!vc->vc_sw->con_font_copy)
+               rc = -ENOSYS;
+       else if (con < 0 || !vc_cons_allocated(con))
+               rc = -ENOTTY;
+       else if (con == vc->vc_num)     /* nothing to do */
+               rc = 0;
+       else
+               rc = vc->vc_sw->con_font_copy(vc, con);
+       release_console_sem();
+       return rc;
+}
+
+int con_font_op(struct vc_data *vc, struct console_font_op *op)
+{
+       switch (op->op) {
+       case KD_FONT_OP_SET:
+               return con_font_set(vc, op);
+       case KD_FONT_OP_GET:
+               return con_font_get(vc, op);
+       case KD_FONT_OP_SET_DEFAULT:
+               return con_font_default(vc, op);
+       case KD_FONT_OP_COPY:
+               return con_font_copy(vc, op);
+       }
+       return -ENOSYS;
+}
+
+/*
+ *     Interface exported to selection and vcs.
+ */
+
+/* used by selection */
+u16 screen_glyph(struct vc_data *vc, int offset)
+{
+       u16 w = scr_readw(screenpos(vc, offset, 1));
+       u16 c = w & 0xff;
+
+       if (w & vc->vc_hi_font_mask)
+               c |= 0x100;
+       return c;
+}
+EXPORT_SYMBOL_GPL(screen_glyph);
+
+/* used by vcs - note the word offset */
+unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
+{
+       return screenpos(vc, 2 * w_offset, viewed);
+}
+
+void getconsxy(struct vc_data *vc, unsigned char *p)
+{
+       p[0] = vc->vc_x;
+       p[1] = vc->vc_y;
+}
+
+void putconsxy(struct vc_data *vc, unsigned char *p)
+{
+       hide_cursor(vc);
+       gotoxy(vc, p[0], p[1]);
+       set_cursor(vc);
+}
+
+u16 vcs_scr_readw(struct vc_data *vc, const u16 *org)
+{
+       if ((unsigned long)org == vc->vc_pos && softcursor_original != -1)
+               return softcursor_original;
+       return scr_readw(org);
+}
+
+void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org)
+{
+       scr_writew(val, org);
+       if ((unsigned long)org == vc->vc_pos) {
+               softcursor_original = -1;
+               add_softcursor(vc);
+       }
+}
+
+void vcs_scr_updated(struct vc_data *vc)
+{
+       notify_update(vc);
+}
+
+/*
+ *     Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(color_table);
+EXPORT_SYMBOL(default_red);
+EXPORT_SYMBOL(default_grn);
+EXPORT_SYMBOL(default_blu);
+EXPORT_SYMBOL(update_region);
+EXPORT_SYMBOL(redraw_screen);
+EXPORT_SYMBOL(vc_resize);
+EXPORT_SYMBOL(fg_console);
+EXPORT_SYMBOL(console_blank_hook);
+EXPORT_SYMBOL(console_blanked);
+EXPORT_SYMBOL(vc_cons);
+EXPORT_SYMBOL(global_cursor_default);
+#ifndef VT_SINGLE_DRIVER
+EXPORT_SYMBOL(take_over_console);
+EXPORT_SYMBOL(give_up_console);
+#endif
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
new file mode 100644 (file)
index 0000000..6b68a0f
--- /dev/null
@@ -0,0 +1,1788 @@
+/*
+ *  linux/drivers/char/vt_ioctl.c
+ *
+ *  Copyright (C) 1992 obz under the linux copyright
+ *
+ *  Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
+ *  Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
+ *  Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995
+ *  Some code moved for less code duplication - Andi Kleen - Mar 1997
+ *  Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/compat.h>
+#include <linux/module.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/console.h>
+#include <linux/consolemap.h>
+#include <linux/signal.h>
+#include <linux/smp_lock.h>
+#include <linux/timex.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/kbd_diacr.h>
+#include <linux/selection.h>
+
+char vt_dont_switch;
+extern struct tty_driver *console_driver;
+
+#define VT_IS_IN_USE(i)        (console_driver->ttys[i] && console_driver->ttys[i]->count)
+#define VT_BUSY(i)     (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons)
+
+/*
+ * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
+ * experimentation and study of X386 SYSV handling.
+ *
+ * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
+ * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
+ * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
+ * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to
+ * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using
+ * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing
+ * to the current console is done by the main ioctl code.
+ */
+
+#ifdef CONFIG_X86
+#include <linux/syscalls.h>
+#endif
+
+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.oldev = old + 1;
+               ve->event.newev = 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_tty(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.newev != n);
+       return 0;
+}
+
+/*
+ * these are the valid i/o ports we're allowed to change. they map all the
+ * video ports
+ */
+#define GPFIRST 0x3b4
+#define GPLAST 0x3df
+#define GPNUM (GPLAST - GPFIRST + 1)
+
+#define i (tmp.kb_index)
+#define s (tmp.kb_table)
+#define v (tmp.kb_value)
+static inline int
+do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd)
+{
+       struct kbentry tmp;
+       ushort *key_map, val, ov;
+
+       if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
+               return -EFAULT;
+
+       if (!capable(CAP_SYS_TTY_CONFIG))
+               perm = 0;
+
+       switch (cmd) {
+       case KDGKBENT:
+               key_map = key_maps[s];
+               if (key_map) {
+                   val = U(key_map[i]);
+                   if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
+                       val = K_HOLE;
+               } else
+                   val = (i ? K_HOLE : K_NOSUCHMAP);
+               return put_user(val, &user_kbe->kb_value);
+       case KDSKBENT:
+               if (!perm)
+                       return -EPERM;
+               if (!i && v == K_NOSUCHMAP) {
+                       /* deallocate map */
+                       key_map = key_maps[s];
+                       if (s && key_map) {
+                           key_maps[s] = NULL;
+                           if (key_map[0] == U(K_ALLOCATED)) {
+                                       kfree(key_map);
+                                       keymap_count--;
+                           }
+                       }
+                       break;
+               }
+
+               if (KTYP(v) < NR_TYPES) {
+                   if (KVAL(v) > max_vals[KTYP(v)])
+                               return -EINVAL;
+               } else
+                   if (kbd->kbdmode != VC_UNICODE)
+                               return -EINVAL;
+
+               /* ++Geert: non-PC keyboards may generate keycode zero */
+#if !defined(__mc68000__) && !defined(__powerpc__)
+               /* assignment to entry 0 only tests validity of args */
+               if (!i)
+                       break;
+#endif
+
+               if (!(key_map = key_maps[s])) {
+                       int j;
+
+                       if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
+                           !capable(CAP_SYS_RESOURCE))
+                               return -EPERM;
+
+                       key_map = kmalloc(sizeof(plain_map),
+                                                    GFP_KERNEL);
+                       if (!key_map)
+                               return -ENOMEM;
+                       key_maps[s] = key_map;
+                       key_map[0] = U(K_ALLOCATED);
+                       for (j = 1; j < NR_KEYS; j++)
+                               key_map[j] = U(K_HOLE);
+                       keymap_count++;
+               }
+               ov = U(key_map[i]);
+               if (v == ov)
+                       break;  /* nothing to do */
+               /*
+                * Attention Key.
+                */
+               if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               key_map[i] = U(v);
+               if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
+                       compute_shiftstate();
+               break;
+       }
+       return 0;
+}
+#undef i
+#undef s
+#undef v
+
+static inline int 
+do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm)
+{
+       struct kbkeycode tmp;
+       int kc = 0;
+
+       if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
+               return -EFAULT;
+       switch (cmd) {
+       case KDGETKEYCODE:
+               kc = getkeycode(tmp.scancode);
+               if (kc >= 0)
+                       kc = put_user(kc, &user_kbkc->keycode);
+               break;
+       case KDSETKEYCODE:
+               if (!perm)
+                       return -EPERM;
+               kc = setkeycode(tmp.scancode, tmp.keycode);
+               break;
+       }
+       return kc;
+}
+
+static inline int
+do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
+{
+       struct kbsentry *kbs;
+       char *p;
+       u_char *q;
+       u_char __user *up;
+       int sz;
+       int delta;
+       char *first_free, *fj, *fnw;
+       int i, j, k;
+       int ret;
+
+       if (!capable(CAP_SYS_TTY_CONFIG))
+               perm = 0;
+
+       kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
+       if (!kbs) {
+               ret = -ENOMEM;
+               goto reterr;
+       }
+
+       /* we mostly copy too much here (512bytes), but who cares ;) */
+       if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
+               ret = -EFAULT;
+               goto reterr;
+       }
+       kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
+       i = kbs->kb_func;
+
+       switch (cmd) {
+       case KDGKBSENT:
+               sz = sizeof(kbs->kb_string) - 1; /* sz should have been
+                                                 a struct member */
+               up = user_kdgkb->kb_string;
+               p = func_table[i];
+               if(p)
+                       for ( ; *p && sz; p++, sz--)
+                               if (put_user(*p, up++)) {
+                                       ret = -EFAULT;
+                                       goto reterr;
+                               }
+               if (put_user('\0', up)) {
+                       ret = -EFAULT;
+                       goto reterr;
+               }
+               kfree(kbs);
+               return ((p && *p) ? -EOVERFLOW : 0);
+       case KDSKBSENT:
+               if (!perm) {
+                       ret = -EPERM;
+                       goto reterr;
+               }
+
+               q = func_table[i];
+               first_free = funcbufptr + (funcbufsize - funcbufleft);
+               for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) 
+                       ;
+               if (j < MAX_NR_FUNC)
+                       fj = func_table[j];
+               else
+                       fj = first_free;
+
+               delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
+               if (delta <= funcbufleft) {     /* it fits in current buf */
+                   if (j < MAX_NR_FUNC) {
+                       memmove(fj + delta, fj, first_free - fj);
+                       for (k = j; k < MAX_NR_FUNC; k++)
+                           if (func_table[k])
+                               func_table[k] += delta;
+                   }
+                   if (!q)
+                     func_table[i] = fj;
+                   funcbufleft -= delta;
+               } else {                        /* allocate a larger buffer */
+                   sz = 256;
+                   while (sz < funcbufsize - funcbufleft + delta)
+                     sz <<= 1;
+                   fnw = kmalloc(sz, GFP_KERNEL);
+                   if(!fnw) {
+                     ret = -ENOMEM;
+                     goto reterr;
+                   }
+
+                   if (!q)
+                     func_table[i] = fj;
+                   if (fj > funcbufptr)
+                       memmove(fnw, funcbufptr, fj - funcbufptr);
+                   for (k = 0; k < j; k++)
+                     if (func_table[k])
+                       func_table[k] = fnw + (func_table[k] - funcbufptr);
+
+                   if (first_free > fj) {
+                       memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
+                       for (k = j; k < MAX_NR_FUNC; k++)
+                         if (func_table[k])
+                           func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
+                   }
+                   if (funcbufptr != func_buf)
+                     kfree(funcbufptr);
+                   funcbufptr = fnw;
+                   funcbufleft = funcbufleft - delta + sz - funcbufsize;
+                   funcbufsize = sz;
+               }
+               strcpy(func_table[i], kbs->kb_string);
+               break;
+       }
+       ret = 0;
+reterr:
+       kfree(kbs);
+       return ret;
+}
+
+static inline int 
+do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op)
+{
+       struct consolefontdesc cfdarg;
+       int i;
+
+       if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) 
+               return -EFAULT;
+       
+       switch (cmd) {
+       case PIO_FONTX:
+               if (!perm)
+                       return -EPERM;
+               op->op = KD_FONT_OP_SET;
+               op->flags = KD_FONT_FLAG_OLD;
+               op->width = 8;
+               op->height = cfdarg.charheight;
+               op->charcount = cfdarg.charcount;
+               op->data = cfdarg.chardata;
+               return con_font_op(vc_cons[fg_console].d, op);
+       case GIO_FONTX: {
+               op->op = KD_FONT_OP_GET;
+               op->flags = KD_FONT_FLAG_OLD;
+               op->width = 8;
+               op->height = cfdarg.charheight;
+               op->charcount = cfdarg.charcount;
+               op->data = cfdarg.chardata;
+               i = con_font_op(vc_cons[fg_console].d, op);
+               if (i)
+                       return i;
+               cfdarg.charheight = op->height;
+               cfdarg.charcount = op->charcount;
+               if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc)))
+                       return -EFAULT;
+               return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+static inline int 
+do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc)
+{
+       struct unimapdesc tmp;
+
+       if (copy_from_user(&tmp, user_ud, sizeof tmp))
+               return -EFAULT;
+       if (tmp.entries)
+               if (!access_ok(VERIFY_WRITE, tmp.entries,
+                               tmp.entry_ct*sizeof(struct unipair)))
+                       return -EFAULT;
+       switch (cmd) {
+       case PIO_UNIMAP:
+               if (!perm)
+                       return -EPERM;
+               return con_set_unimap(vc, tmp.entry_ct, tmp.entries);
+       case GIO_UNIMAP:
+               if (!perm && fg_console != vc->vc_num)
+                       return -EPERM;
+               return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
+       }
+       return 0;
+}
+
+
+
+/*
+ * We handle the console-specific ioctl's here.  We allow the
+ * capability to modify any console, not just the fg_console. 
+ */
+int vt_ioctl(struct tty_struct *tty, struct file * file,
+            unsigned int cmd, unsigned long arg)
+{
+       struct vc_data *vc = tty->driver_data;
+       struct console_font_op op;      /* used in multiple places here */
+       struct kbd_struct * kbd;
+       unsigned int console;
+       unsigned char ucval;
+       unsigned int uival;
+       void __user *up = (void __user *)arg;
+       int i, perm;
+       int ret = 0;
+
+       console = vc->vc_num;
+
+       tty_lock();
+
+       if (!vc_cons_allocated(console)) {      /* impossible? */
+               ret = -ENOIOCTLCMD;
+               goto out;
+       }
+
+
+       /*
+        * To have permissions to do most of the vt ioctls, we either have
+        * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
+        */
+       perm = 0;
+       if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
+               perm = 1;
+       kbd = kbd_table + console;
+       switch (cmd) {
+       case TIOCLINUX:
+               ret = tioclinux(tty, arg);
+               break;
+       case KIOCSOUND:
+               if (!perm)
+                       goto eperm;
+               /*
+                * The use of PIT_TICK_RATE is historic, it used to be
+                * the platform-dependent CLOCK_TICK_RATE between 2.6.12
+                * and 2.6.36, which was a minor but unfortunate ABI
+                * change.
+                */
+               if (arg)
+                       arg = PIT_TICK_RATE / arg;
+               kd_mksound(arg, 0);
+               break;
+
+       case KDMKTONE:
+               if (!perm)
+                       goto eperm;
+       {
+               unsigned int ticks, count;
+               
+               /*
+                * Generate the tone for the appropriate number of ticks.
+                * If the time is zero, turn off sound ourselves.
+                */
+               ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
+               count = ticks ? (arg & 0xffff) : 0;
+               if (count)
+                       count = PIT_TICK_RATE / count;
+               kd_mksound(count, ticks);
+               break;
+       }
+
+       case KDGKBTYPE:
+               /*
+                * this is naive.
+                */
+               ucval = KB_101;
+               goto setchar;
+
+               /*
+                * These cannot be implemented on any machine that implements
+                * ioperm() in user level (such as Alpha PCs) or not at all.
+                *
+                * XXX: you should never use these, just call ioperm directly..
+                */
+#ifdef CONFIG_X86
+       case KDADDIO:
+       case KDDELIO:
+               /*
+                * KDADDIO and KDDELIO may be able to add ports beyond what
+                * we reject here, but to be safe...
+                */
+               if (arg < GPFIRST || arg > GPLAST) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
+               break;
+
+       case KDENABIO:
+       case KDDISABIO:
+               ret = sys_ioperm(GPFIRST, GPNUM,
+                                 (cmd == KDENABIO)) ? -ENXIO : 0;
+               break;
+#endif
+
+       /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */
+               
+       case KDKBDREP:
+       {
+               struct kbd_repeat kbrep;
+               
+               if (!capable(CAP_SYS_TTY_CONFIG))
+                       goto eperm;
+
+               if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
+                       ret =  -EFAULT;
+                       break;
+               }
+               ret = kbd_rate(&kbrep);
+               if (ret)
+                       break;
+               if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat)))
+                       ret = -EFAULT;
+               break;
+       }
+
+       case KDSETMODE:
+               /*
+                * currently, setting the mode from KD_TEXT to KD_GRAPHICS
+                * doesn't do a whole lot. i'm not sure if it should do any
+                * restoration of modes or what...
+                *
+                * XXX It should at least call into the driver, fbdev's definitely
+                * need to restore their engine state. --BenH
+                */
+               if (!perm)
+                       goto eperm;
+               switch (arg) {
+               case KD_GRAPHICS:
+                       break;
+               case KD_TEXT0:
+               case KD_TEXT1:
+                       arg = KD_TEXT;
+               case KD_TEXT:
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto out;
+               }
+               if (vc->vc_mode == (unsigned char) arg)
+                       break;
+               vc->vc_mode = (unsigned char) arg;
+               if (console != fg_console)
+                       break;
+               /*
+                * explicitly blank/unblank the screen if switching modes
+                */
+               acquire_console_sem();
+               if (arg == KD_TEXT)
+                       do_unblank_screen(1);
+               else
+                       do_blank_screen(1);
+               release_console_sem();
+               break;
+
+       case KDGETMODE:
+               uival = vc->vc_mode;
+               goto setint;
+
+       case KDMAPDISP:
+       case KDUNMAPDISP:
+               /*
+                * these work like a combination of mmap and KDENABIO.
+                * this could be easily finished.
+                */
+               ret = -EINVAL;
+               break;
+
+       case KDSKBMODE:
+               if (!perm)
+                       goto eperm;
+               switch(arg) {
+                 case K_RAW:
+                       kbd->kbdmode = VC_RAW;
+                       break;
+                 case K_MEDIUMRAW:
+                       kbd->kbdmode = VC_MEDIUMRAW;
+                       break;
+                 case K_XLATE:
+                       kbd->kbdmode = VC_XLATE;
+                       compute_shiftstate();
+                       break;
+                 case K_UNICODE:
+                       kbd->kbdmode = VC_UNICODE;
+                       compute_shiftstate();
+                       break;
+                 default:
+                       ret = -EINVAL;
+                       goto out;
+               }
+               tty_ldisc_flush(tty);
+               break;
+
+       case KDGKBMODE:
+               uival = ((kbd->kbdmode == VC_RAW) ? K_RAW :
+                                (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
+                                (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
+                                K_XLATE);
+               goto setint;
+
+       /* this could be folded into KDSKBMODE, but for compatibility
+          reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
+       case KDSKBMETA:
+               switch(arg) {
+                 case K_METABIT:
+                       clr_vc_kbd_mode(kbd, VC_META);
+                       break;
+                 case K_ESCPREFIX:
+                       set_vc_kbd_mode(kbd, VC_META);
+                       break;
+                 default:
+                       ret = -EINVAL;
+               }
+               break;
+
+       case KDGKBMETA:
+               uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
+       setint:
+               ret = put_user(uival, (int __user *)arg);
+               break;
+
+       case KDGETKEYCODE:
+       case KDSETKEYCODE:
+               if(!capable(CAP_SYS_TTY_CONFIG))
+                       perm = 0;
+               ret = do_kbkeycode_ioctl(cmd, up, perm);
+               break;
+
+       case KDGKBENT:
+       case KDSKBENT:
+               ret = do_kdsk_ioctl(cmd, up, perm, kbd);
+               break;
+
+       case KDGKBSENT:
+       case KDSKBSENT:
+               ret = do_kdgkb_ioctl(cmd, up, perm);
+               break;
+
+       case KDGKBDIACR:
+       {
+               struct kbdiacrs __user *a = up;
+               struct kbdiacr diacr;
+               int i;
+
+               if (put_user(accent_table_size, &a->kb_cnt)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               for (i = 0; i < accent_table_size; i++) {
+                       diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
+                       diacr.base = conv_uni_to_8bit(accent_table[i].base);
+                       diacr.result = conv_uni_to_8bit(accent_table[i].result);
+                       if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
+                               ret = -EFAULT;
+                               break;
+                       }
+               }
+               break;
+       }
+       case KDGKBDIACRUC:
+       {
+               struct kbdiacrsuc __user *a = up;
+
+               if (put_user(accent_table_size, &a->kb_cnt))
+                       ret = -EFAULT;
+               else if (copy_to_user(a->kbdiacruc, accent_table,
+                               accent_table_size*sizeof(struct kbdiacruc)))
+                       ret = -EFAULT;
+               break;
+       }
+
+       case KDSKBDIACR:
+       {
+               struct kbdiacrs __user *a = up;
+               struct kbdiacr diacr;
+               unsigned int ct;
+               int i;
+
+               if (!perm)
+                       goto eperm;
+               if (get_user(ct,&a->kb_cnt)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (ct >= MAX_DIACR) {
+                       ret = -EINVAL;
+                       break;
+               }
+               accent_table_size = ct;
+               for (i = 0; i < ct; i++) {
+                       if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
+                               ret = -EFAULT;
+                               break;
+                       }
+                       accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
+                       accent_table[i].base = conv_8bit_to_uni(diacr.base);
+                       accent_table[i].result = conv_8bit_to_uni(diacr.result);
+               }
+               break;
+       }
+
+       case KDSKBDIACRUC:
+       {
+               struct kbdiacrsuc __user *a = up;
+               unsigned int ct;
+
+               if (!perm)
+                       goto eperm;
+               if (get_user(ct,&a->kb_cnt)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (ct >= MAX_DIACR) {
+                       ret = -EINVAL;
+                       break;
+               }
+               accent_table_size = ct;
+               if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
+                       ret = -EFAULT;
+               break;
+       }
+
+       /* the ioctls below read/set the flags usually shown in the leds */
+       /* don't use them - they will go away without warning */
+       case KDGKBLED:
+               ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
+               goto setchar;
+
+       case KDSKBLED:
+               if (!perm)
+                       goto eperm;
+               if (arg & ~0x77) {
+                       ret = -EINVAL;
+                       break;
+               }
+               kbd->ledflagstate = (arg & 7);
+               kbd->default_ledflagstate = ((arg >> 4) & 7);
+               set_leds();
+               break;
+
+       /* the ioctls below only set the lights, not the functions */
+       /* for those, see KDGKBLED and KDSKBLED above */
+       case KDGETLED:
+               ucval = getledstate();
+       setchar:
+               ret = put_user(ucval, (char __user *)arg);
+               break;
+
+       case KDSETLED:
+               if (!perm)
+                       goto eperm;
+               setledstate(kbd, arg);
+               break;
+
+       /*
+        * A process can indicate its willingness to accept signals
+        * generated by pressing an appropriate key combination.
+        * Thus, one can have a daemon that e.g. spawns a new console
+        * upon a keypress and then changes to it.
+        * See also the kbrequest field of inittab(5).
+        */
+       case KDSIGACCEPT:
+       {
+               if (!perm || !capable(CAP_KILL))
+                       goto eperm;
+               if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
+                       ret = -EINVAL;
+               else {
+                       spin_lock_irq(&vt_spawn_con.lock);
+                       put_pid(vt_spawn_con.pid);
+                       vt_spawn_con.pid = get_pid(task_pid(current));
+                       vt_spawn_con.sig = arg;
+                       spin_unlock_irq(&vt_spawn_con.lock);
+               }
+               break;
+       }
+
+       case VT_SETMODE:
+       {
+               struct vt_mode tmp;
+
+               if (!perm)
+                       goto eperm;
+               if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+               if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+               acquire_console_sem();
+               vc->vt_mode = tmp;
+               /* the frsig is ignored, so we set it to 0 */
+               vc->vt_mode.frsig = 0;
+               put_pid(vc->vt_pid);
+               vc->vt_pid = get_pid(task_pid(current));
+               /* no switch is required -- saw@shade.msu.ru */
+               vc->vt_newvt = -1;
+               release_console_sem();
+               break;
+       }
+
+       case VT_GETMODE:
+       {
+               struct vt_mode tmp;
+               int rc;
+
+               acquire_console_sem();
+               memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode));
+               release_console_sem();
+
+               rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
+               if (rc)
+                       ret = -EFAULT;
+               break;
+       }
+
+       /*
+        * Returns global vt state. Note that VT 0 is always open, since
+        * it's an alias for the current VT, and people can't use it here.
+        * We cannot return state for more than 16 VTs, since v_state is short.
+        */
+       case VT_GETSTATE:
+       {
+               struct vt_stat __user *vtstat = up;
+               unsigned short state, mask;
+
+               if (put_user(fg_console + 1, &vtstat->v_active))
+                       ret = -EFAULT;
+               else {
+                       state = 1;      /* /dev/tty0 is always open */
+                       for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
+                                                       ++i, mask <<= 1)
+                               if (VT_IS_IN_USE(i))
+                                       state |= mask;
+                       ret = put_user(state, &vtstat->v_state);
+               }
+               break;
+       }
+
+       /*
+        * Returns the first available (non-opened) console.
+        */
+       case VT_OPENQRY:
+               for (i = 0; i < MAX_NR_CONSOLES; ++i)
+                       if (! VT_IS_IN_USE(i))
+                               break;
+               uival = i < MAX_NR_CONSOLES ? (i+1) : -1;
+               goto setint;             
+
+       /*
+        * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
+        * with num >= 1 (switches to vt 0, our console, are not allowed, just
+        * to preserve sanity).
+        */
+       case VT_ACTIVATE:
+               if (!perm)
+                       goto eperm;
+               if (arg == 0 || arg > MAX_NR_CONSOLES)
+                       ret =  -ENXIO;
+               else {
+                       arg--;
+                       acquire_console_sem();
+                       ret = vc_allocate(arg);
+                       release_console_sem();
+                       if (ret)
+                               break;
+                       set_console(arg);
+               }
+               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))) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+               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
+        */
+       case VT_WAITACTIVE:
+               if (!perm)
+                       goto eperm;
+               if (arg == 0 || arg > MAX_NR_CONSOLES)
+                       ret = -ENXIO;
+               else
+                       ret = vt_waitactive(arg);
+               break;
+
+       /*
+        * If a vt is under process control, the kernel will not switch to it
+        * immediately, but postpone the operation until the process calls this
+        * ioctl, allowing the switch to complete.
+        *
+        * According to the X sources this is the behavior:
+        *      0:      pending switch-from not OK
+        *      1:      pending switch-from OK
+        *      2:      completed switch-to OK
+        */
+       case VT_RELDISP:
+               if (!perm)
+                       goto eperm;
+
+               if (vc->vt_mode.mode != VT_PROCESS) {
+                       ret = -EINVAL;
+                       break;
+               }
+               /*
+                * Switching-from response
+                */
+               acquire_console_sem();
+               if (vc->vt_newvt >= 0) {
+                       if (arg == 0)
+                               /*
+                                * Switch disallowed, so forget we were trying
+                                * to do it.
+                                */
+                               vc->vt_newvt = -1;
+
+                       else {
+                               /*
+                                * The current vt has been released, so
+                                * complete the switch.
+                                */
+                               int newvt;
+                               newvt = vc->vt_newvt;
+                               vc->vt_newvt = -1;
+                               ret = vc_allocate(newvt);
+                               if (ret) {
+                                       release_console_sem();
+                                       break;
+                               }
+                               /*
+                                * When we actually do the console switch,
+                                * make sure we are atomic with respect to
+                                * other console switches..
+                                */
+                               complete_change_console(vc_cons[newvt].d);
+                       }
+               } else {
+                       /*
+                        * Switched-to response
+                        */
+                       /*
+                        * If it's just an ACK, ignore it
+                        */
+                       if (arg != VT_ACKACQ)
+                               ret = -EINVAL;
+               }
+               release_console_sem();
+               break;
+
+        /*
+         * Disallocate memory associated to VT (but leave VT1)
+         */
+        case VT_DISALLOCATE:
+               if (arg > MAX_NR_CONSOLES) {
+                       ret = -ENXIO;
+                       break;
+               }
+               if (arg == 0) {
+                   /* deallocate all unused consoles, but leave 0 */
+                       acquire_console_sem();
+                       for (i=1; i<MAX_NR_CONSOLES; i++)
+                               if (! VT_BUSY(i))
+                                       vc_deallocate(i);
+                       release_console_sem();
+               } else {
+                       /* deallocate a single console, if possible */
+                       arg--;
+                       if (VT_BUSY(arg))
+                               ret = -EBUSY;
+                       else if (arg) {                       /* leave 0 */
+                               acquire_console_sem();
+                               vc_deallocate(arg);
+                               release_console_sem();
+                       }
+               }
+               break;
+
+       case VT_RESIZE:
+       {
+               struct vt_sizes __user *vtsizes = up;
+               struct vc_data *vc;
+
+               ushort ll,cc;
+               if (!perm)
+                       goto eperm;
+               if (get_user(ll, &vtsizes->v_rows) ||
+                   get_user(cc, &vtsizes->v_cols))
+                       ret = -EFAULT;
+               else {
+                       acquire_console_sem();
+                       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+                               vc = vc_cons[i].d;
+
+                               if (vc) {
+                                       vc->vc_resize_user = 1;
+                                       vc_resize(vc_cons[i].d, cc, ll);
+                               }
+                       }
+                       release_console_sem();
+               }
+               break;
+       }
+
+       case VT_RESIZEX:
+       {
+               struct vt_consize __user *vtconsize = up;
+               ushort ll,cc,vlin,clin,vcol,ccol;
+               if (!perm)
+                       goto eperm;
+               if (!access_ok(VERIFY_READ, vtconsize,
+                               sizeof(struct vt_consize))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               /* FIXME: Should check the copies properly */
+               __get_user(ll, &vtconsize->v_rows);
+               __get_user(cc, &vtconsize->v_cols);
+               __get_user(vlin, &vtconsize->v_vlin);
+               __get_user(clin, &vtconsize->v_clin);
+               __get_user(vcol, &vtconsize->v_vcol);
+               __get_user(ccol, &vtconsize->v_ccol);
+               vlin = vlin ? vlin : vc->vc_scan_lines;
+               if (clin) {
+                       if (ll) {
+                               if (ll != vlin/clin) {
+                                       /* Parameters don't add up */
+                                       ret = -EINVAL;
+                                       break;
+                               }
+                       } else 
+                               ll = vlin/clin;
+               }
+               if (vcol && ccol) {
+                       if (cc) {
+                               if (cc != vcol/ccol) {
+                                       ret = -EINVAL;
+                                       break;
+                               }
+                       } else
+                               cc = vcol/ccol;
+               }
+
+               if (clin > 32) {
+                       ret =  -EINVAL;
+                       break;
+               }
+                   
+               for (i = 0; i < MAX_NR_CONSOLES; i++) {
+                       if (!vc_cons[i].d)
+                               continue;
+                       acquire_console_sem();
+                       if (vlin)
+                               vc_cons[i].d->vc_scan_lines = vlin;
+                       if (clin)
+                               vc_cons[i].d->vc_font.height = clin;
+                       vc_cons[i].d->vc_resize_user = 1;
+                       vc_resize(vc_cons[i].d, cc, ll);
+                       release_console_sem();
+               }
+               break;
+       }
+
+       case PIO_FONT: {
+               if (!perm)
+                       goto eperm;
+               op.op = KD_FONT_OP_SET;
+               op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
+               op.width = 8;
+               op.height = 0;
+               op.charcount = 256;
+               op.data = up;
+               ret = con_font_op(vc_cons[fg_console].d, &op);
+               break;
+       }
+
+       case GIO_FONT: {
+               op.op = KD_FONT_OP_GET;
+               op.flags = KD_FONT_FLAG_OLD;
+               op.width = 8;
+               op.height = 32;
+               op.charcount = 256;
+               op.data = up;
+               ret = con_font_op(vc_cons[fg_console].d, &op);
+               break;
+       }
+
+       case PIO_CMAP:
+                if (!perm)
+                       ret = -EPERM;
+               else
+                       ret = con_set_cmap(up);
+               break;
+
+       case GIO_CMAP:
+                ret = con_get_cmap(up);
+               break;
+
+       case PIO_FONTX:
+       case GIO_FONTX:
+               ret = do_fontx_ioctl(cmd, up, perm, &op);
+               break;
+
+       case PIO_FONTRESET:
+       {
+               if (!perm)
+                       goto eperm;
+
+#ifdef BROKEN_GRAPHICS_PROGRAMS
+               /* With BROKEN_GRAPHICS_PROGRAMS defined, the default
+                  font is not saved. */
+               ret = -ENOSYS;
+               break;
+#else
+               {
+               op.op = KD_FONT_OP_SET_DEFAULT;
+               op.data = NULL;
+               ret = con_font_op(vc_cons[fg_console].d, &op);
+               if (ret)
+                       break;
+               con_set_default_unimap(vc_cons[fg_console].d);
+               break;
+               }
+#endif
+       }
+
+       case KDFONTOP: {
+               if (copy_from_user(&op, up, sizeof(op))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (!perm && op.op != KD_FONT_OP_GET)
+                       goto eperm;
+               ret = con_font_op(vc, &op);
+               if (ret)
+                       break;
+               if (copy_to_user(up, &op, sizeof(op)))
+                       ret = -EFAULT;
+               break;
+       }
+
+       case PIO_SCRNMAP:
+               if (!perm)
+                       ret = -EPERM;
+               else
+                       ret = con_set_trans_old(up);
+               break;
+
+       case GIO_SCRNMAP:
+               ret = con_get_trans_old(up);
+               break;
+
+       case PIO_UNISCRNMAP:
+               if (!perm)
+                       ret = -EPERM;
+               else
+                       ret = con_set_trans_new(up);
+               break;
+
+       case GIO_UNISCRNMAP:
+               ret = con_get_trans_new(up);
+               break;
+
+       case PIO_UNIMAPCLR:
+             { struct unimapinit ui;
+               if (!perm)
+                       goto eperm;
+               ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
+               if (ret)
+                       ret = -EFAULT;
+               else
+                       con_clear_unimap(vc, &ui);
+               break;
+             }
+
+       case PIO_UNIMAP:
+       case GIO_UNIMAP:
+               ret = do_unimap_ioctl(cmd, up, perm, vc);
+               break;
+
+       case VT_LOCKSWITCH:
+               if (!capable(CAP_SYS_TTY_CONFIG))
+                       goto eperm;
+               vt_dont_switch = 1;
+               break;
+       case VT_UNLOCKSWITCH:
+               if (!capable(CAP_SYS_TTY_CONFIG))
+                       goto eperm;
+               vt_dont_switch = 0;
+               break;
+       case VT_GETHIFONTMASK:
+               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;
+       }
+out:
+       tty_unlock();
+       return ret;
+eperm:
+       ret = -EPERM;
+       goto out;
+}
+
+void reset_vc(struct vc_data *vc)
+{
+       vc->vc_mode = KD_TEXT;
+       kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
+       vc->vt_mode.mode = VT_AUTO;
+       vc->vt_mode.waitv = 0;
+       vc->vt_mode.relsig = 0;
+       vc->vt_mode.acqsig = 0;
+       vc->vt_mode.frsig = 0;
+       put_pid(vc->vt_pid);
+       vc->vt_pid = NULL;
+       vc->vt_newvt = -1;
+       if (!in_interrupt())    /* Via keyboard.c:SAK() - akpm */
+               reset_palette(vc);
+}
+
+void vc_SAK(struct work_struct *work)
+{
+       struct vc *vc_con =
+               container_of(work, struct vc, SAK_work);
+       struct vc_data *vc;
+       struct tty_struct *tty;
+
+       acquire_console_sem();
+       vc = vc_con->d;
+       if (vc) {
+               tty = vc->port.tty;
+               /*
+                * SAK should also work in all raw modes and reset
+                * them properly.
+                */
+               if (tty)
+                       __do_SAK(tty);
+               reset_vc(vc);
+       }
+       release_console_sem();
+}
+
+#ifdef CONFIG_COMPAT
+
+struct compat_consolefontdesc {
+       unsigned short charcount;       /* characters in font (256 or 512) */
+       unsigned short charheight;      /* scan lines per character (1-32) */
+       compat_caddr_t chardata;        /* font data in expanded form */
+};
+
+static inline int
+compat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd,
+                        int perm, struct console_font_op *op)
+{
+       struct compat_consolefontdesc cfdarg;
+       int i;
+
+       if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc)))
+               return -EFAULT;
+
+       switch (cmd) {
+       case PIO_FONTX:
+               if (!perm)
+                       return -EPERM;
+               op->op = KD_FONT_OP_SET;
+               op->flags = KD_FONT_FLAG_OLD;
+               op->width = 8;
+               op->height = cfdarg.charheight;
+               op->charcount = cfdarg.charcount;
+               op->data = compat_ptr(cfdarg.chardata);
+               return con_font_op(vc_cons[fg_console].d, op);
+       case GIO_FONTX:
+               op->op = KD_FONT_OP_GET;
+               op->flags = KD_FONT_FLAG_OLD;
+               op->width = 8;
+               op->height = cfdarg.charheight;
+               op->charcount = cfdarg.charcount;
+               op->data = compat_ptr(cfdarg.chardata);
+               i = con_font_op(vc_cons[fg_console].d, op);
+               if (i)
+                       return i;
+               cfdarg.charheight = op->height;
+               cfdarg.charcount = op->charcount;
+               if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc)))
+                       return -EFAULT;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+struct compat_console_font_op {
+       compat_uint_t op;        /* operation code KD_FONT_OP_* */
+       compat_uint_t flags;     /* KD_FONT_FLAG_* */
+       compat_uint_t width, height;     /* font size */
+       compat_uint_t charcount;
+       compat_caddr_t data;    /* font data with height fixed to 32 */
+};
+
+static inline int
+compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop,
+                        int perm, struct console_font_op *op, struct vc_data *vc)
+{
+       int i;
+
+       if (copy_from_user(op, fontop, sizeof(struct compat_console_font_op)))
+               return -EFAULT;
+       if (!perm && op->op != KD_FONT_OP_GET)
+               return -EPERM;
+       op->data = compat_ptr(((struct compat_console_font_op *)op)->data);
+       op->flags |= KD_FONT_FLAG_OLD;
+       i = con_font_op(vc, op);
+       if (i)
+               return i;
+       ((struct compat_console_font_op *)op)->data = (unsigned long)op->data;
+       if (copy_to_user(fontop, op, sizeof(struct compat_console_font_op)))
+               return -EFAULT;
+       return 0;
+}
+
+struct compat_unimapdesc {
+       unsigned short entry_ct;
+       compat_caddr_t entries;
+};
+
+static inline int
+compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
+                        int perm, struct vc_data *vc)
+{
+       struct compat_unimapdesc tmp;
+       struct unipair __user *tmp_entries;
+
+       if (copy_from_user(&tmp, user_ud, sizeof tmp))
+               return -EFAULT;
+       tmp_entries = compat_ptr(tmp.entries);
+       if (tmp_entries)
+               if (!access_ok(VERIFY_WRITE, tmp_entries,
+                               tmp.entry_ct*sizeof(struct unipair)))
+                       return -EFAULT;
+       switch (cmd) {
+       case PIO_UNIMAP:
+               if (!perm)
+                       return -EPERM;
+               return con_set_unimap(vc, tmp.entry_ct, tmp_entries);
+       case GIO_UNIMAP:
+               if (!perm && fg_console != vc->vc_num)
+                       return -EPERM;
+               return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp_entries);
+       }
+       return 0;
+}
+
+long vt_compat_ioctl(struct tty_struct *tty, struct file * file,
+            unsigned int cmd, unsigned long arg)
+{
+       struct vc_data *vc = tty->driver_data;
+       struct console_font_op op;      /* used in multiple places here */
+       struct kbd_struct *kbd;
+       unsigned int console;
+       void __user *up = (void __user *)arg;
+       int perm;
+       int ret = 0;
+
+       console = vc->vc_num;
+
+       tty_lock();
+
+       if (!vc_cons_allocated(console)) {      /* impossible? */
+               ret = -ENOIOCTLCMD;
+               goto out;
+       }
+
+       /*
+        * To have permissions to do most of the vt ioctls, we either have
+        * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
+        */
+       perm = 0;
+       if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
+               perm = 1;
+
+       kbd = kbd_table + console;
+       switch (cmd) {
+       /*
+        * these need special handlers for incompatible data structures
+        */
+       case PIO_FONTX:
+       case GIO_FONTX:
+               ret = compat_fontx_ioctl(cmd, up, perm, &op);
+               break;
+
+       case KDFONTOP:
+               ret = compat_kdfontop_ioctl(up, perm, &op, vc);
+               break;
+
+       case PIO_UNIMAP:
+       case GIO_UNIMAP:
+               ret = compat_unimap_ioctl(cmd, up, perm, vc);
+               break;
+
+       /*
+        * all these treat 'arg' as an integer
+        */
+       case KIOCSOUND:
+       case KDMKTONE:
+#ifdef CONFIG_X86
+       case KDADDIO:
+       case KDDELIO:
+#endif
+       case KDSETMODE:
+       case KDMAPDISP:
+       case KDUNMAPDISP:
+       case KDSKBMODE:
+       case KDSKBMETA:
+       case KDSKBLED:
+       case KDSETLED:
+       case KDSIGACCEPT:
+       case VT_ACTIVATE:
+       case VT_WAITACTIVE:
+       case VT_RELDISP:
+       case VT_DISALLOCATE:
+       case VT_RESIZE:
+       case VT_RESIZEX:
+               goto fallback;
+
+       /*
+        * the rest has a compatible data structure behind arg,
+        * but we have to convert it to a proper 64 bit pointer.
+        */
+       default:
+               arg = (unsigned long)compat_ptr(arg);
+               goto fallback;
+       }
+out:
+       tty_unlock();
+       return ret;
+
+fallback:
+       tty_unlock();
+       return vt_ioctl(tty, file, cmd, arg);
+}
+
+
+#endif /* CONFIG_COMPAT */
+
+
+/*
+ * 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;
+
+       /*
+        * If we're switching, we could be going from KD_GRAPHICS to
+        * KD_TEXT mode or vice versa, which means we need to blank or
+        * unblank the screen later.
+        */
+       old_vc_mode = vc_cons[fg_console].d->vc_mode;
+       switch_screen(vc);
+
+       /*
+        * This can't appear below a successful kill_pid().  If it did,
+        * then the *blank_screen operation could occur while X, having
+        * received acqsig, is waking up on another processor.  This
+        * condition can lead to overlapping accesses to the VGA range
+        * and the framebuffer (causing system lockups).
+        *
+        * To account for this we duplicate this code below only if the
+        * controlling process is gone and we've called reset_vc.
+        */
+       if (old_vc_mode != vc->vc_mode) {
+               if (vc->vc_mode == KD_TEXT)
+                       do_unblank_screen(1);
+               else
+                       do_blank_screen(1);
+       }
+
+       /*
+        * If this new console is under process control, send it a signal
+        * telling it that it has acquired. Also check if it has died and
+        * clean up (similar to logic employed in change_console())
+        */
+       if (vc->vt_mode.mode == VT_PROCESS) {
+               /*
+                * Send the signal as privileged - kill_pid() will
+                * tell us if the process has gone or something else
+                * is awry
+                */
+               if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) {
+               /*
+                * The controlling process has died, so we revert back to
+                * normal operation. In this case, we'll also change back
+                * to KD_TEXT mode. I'm not sure if this is strictly correct
+                * but it saves the agony when the X server dies and the screen
+                * remains blanked due to KD_GRAPHICS! It would be nice to do
+                * this outside of VT_PROCESS but there is no single process
+                * to account for and tracking tty count may be undesirable.
+                */
+                       reset_vc(vc);
+
+                       if (old_vc_mode != vc->vc_mode) {
+                               if (vc->vc_mode == KD_TEXT)
+                                       do_unblank_screen(1);
+                               else
+                                       do_blank_screen(1);
+                       }
+               }
+       }
+
+       /*
+        * Wake anyone waiting for their VT to activate
+        */
+       vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num);
+       return;
+}
+
+/*
+ * Performs the front-end of a vt switch
+ */
+void change_console(struct vc_data *new_vc)
+{
+       struct vc_data *vc;
+
+       if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch)
+               return;
+
+       /*
+        * If this vt is in process mode, then we need to handshake with
+        * that process before switching. Essentially, we store where that
+        * vt wants to switch to and wait for it to tell us when it's done
+        * (via VT_RELDISP ioctl).
+        *
+        * We also check to see if the controlling process still exists.
+        * If it doesn't, we reset this vt to auto mode and continue.
+        * This is a cheap way to track process control. The worst thing
+        * that can happen is: we send a signal to a process, it dies, and
+        * the switch gets "lost" waiting for a response; hopefully, the
+        * user will try again, we'll detect the process is gone (unless
+        * the user waits just the right amount of time :-) and revert the
+        * vt to auto control.
+        */
+       vc = vc_cons[fg_console].d;
+       if (vc->vt_mode.mode == VT_PROCESS) {
+               /*
+                * Send the signal as privileged - kill_pid() will
+                * tell us if the process has gone or something else
+                * is awry.
+                *
+                * We need to set vt_newvt *before* sending the signal or we
+                * have a race.
+                */
+               vc->vt_newvt = new_vc->vc_num;
+               if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
+                       /*
+                        * It worked. Mark the vt to switch to and
+                        * return. The process needs to send us a
+                        * VT_RELDISP ioctl to complete the switch.
+                        */
+                       return;
+               }
+
+               /*
+                * The controlling process has died, so we revert back to
+                * normal operation. In this case, we'll also change back
+                * to KD_TEXT mode. I'm not sure if this is strictly correct
+                * but it saves the agony when the X server dies and the screen
+                * remains blanked due to KD_GRAPHICS! It would be nice to do
+                * this outside of VT_PROCESS but there is no single process
+                * to account for and tracking tty count may be undesirable.
+                */
+               reset_vc(vc);
+
+               /*
+                * Fall through to normal (VT_AUTO) handling of the switch...
+                */
+       }
+
+       /*
+        * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
+        */
+       if (vc->vc_mode == KD_GRAPHICS)
+               return;
+
+       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();
+       tty_lock();
+       if (vt_waitactive(vt + 1)) {
+               pr_debug("Suspend: Can't switch VCs.");
+               tty_unlock();
+               return -EINTR;
+       }
+       tty_unlock();
+       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);
index cb23355f52d3d8b5335dbdf1e5b07a32c77b281a..fbe86ca95802b93d68ace2718280a4aeb8b533c2 100644 (file)
@@ -811,7 +811,6 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
                INFO(dev, "MAC %pM\n", net->dev_addr);
                INFO(dev, "HOST MAC %pM\n", dev->host_mac);
 
-               netif_stop_queue(net);
                the_dev = dev;
        }
 
index 5aff46c61e521cbaef027b92d1a4bdd7bb86c547..355abcdcda980acfcd70dcb54d4bb798edf6fcae 100644 (file)
@@ -81,7 +81,7 @@ u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for
 
 v) mount check for unmatched uids
 
-w) Add support for new vfs entry points for setlease and fallocate 
+w) Add support for new vfs entry point for fallocate
 
 x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of 
 processes can proceed better in parallel (on the server)
index 525ba59a41058a6d13f4311fb841eb2604a00140..e9a393c9c2ca4ddb8ec3d75cfcf0766234ec1789 100644 (file)
@@ -15,7 +15,7 @@
  *   the GNU Lesser General Public License for more details.
  *
  */
-#include <linux/radix-tree.h>
+#include <linux/rbtree.h>
 
 #ifndef _CIFS_FS_SB_H
 #define _CIFS_FS_SB_H
@@ -42,9 +42,9 @@
 #define CIFS_MOUNT_MULTIUSER   0x20000 /* multiuser mount */
 
 struct cifs_sb_info {
-       struct radix_tree_root tlink_tree;
-#define CIFS_TLINK_MASTER_TAG          0       /* is "master" (mount) tcon */
+       struct rb_root tlink_tree;
        spinlock_t tlink_tree_lock;
+       struct tcon_link *master_tlink;
        struct nls_table *local_nls;
        unsigned int rsize;
        unsigned int wsize;
index 54745b6c3db9c50af75b393c8b80d96460439c80..9c3789762ab7c4c92a7d67859c34b32cb196f1ab 100644 (file)
@@ -116,7 +116,7 @@ cifs_read_super(struct super_block *sb, void *data,
                return -ENOMEM;
 
        spin_lock_init(&cifs_sb->tlink_tree_lock);
-       INIT_RADIX_TREE(&cifs_sb->tlink_tree, GFP_KERNEL);
+       cifs_sb->tlink_tree = RB_ROOT;
 
        rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY);
        if (rc) {
@@ -321,8 +321,7 @@ cifs_alloc_inode(struct super_block *sb)
        /* Until the file is open and we have gotten oplock
        info back from the server, can not assume caching of
        file data or metadata */
-       cifs_inode->clientCanCacheRead = false;
-       cifs_inode->clientCanCacheAll = false;
+       cifs_set_oplock_level(cifs_inode, 0);
        cifs_inode->delete_pending = false;
        cifs_inode->invalid_mapping = false;
        cifs_inode->vfs_inode.i_blkbits = 14;  /* 2**14 = CIFS_MAX_MSGSIZE */
@@ -625,11 +624,8 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
                   knows that the file won't be changed on the server
                   by anyone else */
                return generic_setlease(file, arg, lease);
-       else {
-               if (arg != F_UNLCK)
-                       locks_free_lock(*lease);
+       else
                return -EAGAIN;
-       }
 }
 
 struct file_system_type cifs_fs_type = {
index f259e4d7612d5f2a50f70f6b65802b4fff01621c..b577bf0a1bb3622491ed0a885ca30b9e7684d24e 100644 (file)
@@ -336,7 +336,8 @@ struct cifsTconInfo {
  * "get" on the container.
  */
 struct tcon_link {
-       unsigned long           tl_index;
+       struct rb_node          tl_rbnode;
+       uid_t                   tl_uid;
        unsigned long           tl_flags;
 #define TCON_LINK_MASTER       0
 #define TCON_LINK_PENDING      1
index edb6d90efdf27ac2272c961c7269fbbfab2c0aa7..7ed69b6b5fe6719f66ed5af0a0b38d2cda1aa352 100644 (file)
@@ -104,6 +104,7 @@ extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
 extern u64 cifs_UnixTimeToNT(struct timespec);
 extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
                                      int offset);
+extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
 
 extern struct cifsFileInfo *cifs_new_fileinfo(__u16 fileHandle,
                                struct file *file, struct tcon_link *tlink,
index 9eb327defa1d39fc16d1c8f0837de36a65e43c92..251a17c03545dfc35e8ab37e1ea5a612e94f7536 100644 (file)
@@ -116,6 +116,7 @@ struct smb_vol {
 
 static int ipv4_connect(struct TCP_Server_Info *server);
 static int ipv6_connect(struct TCP_Server_Info *server);
+static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
 static void cifs_prune_tlinks(struct work_struct *work);
 
 /*
@@ -2900,24 +2901,16 @@ remote_path_check:
                goto mount_fail_check;
        }
 
-       tlink->tl_index = pSesInfo->linux_uid;
+       tlink->tl_uid = pSesInfo->linux_uid;
        tlink->tl_tcon = tcon;
        tlink->tl_time = jiffies;
        set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
        set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
 
-       rc = radix_tree_preload(GFP_KERNEL);
-       if (rc == -ENOMEM) {
-               kfree(tlink);
-               goto mount_fail_check;
-       }
-
+       cifs_sb->master_tlink = tlink;
        spin_lock(&cifs_sb->tlink_tree_lock);
-       radix_tree_insert(&cifs_sb->tlink_tree, pSesInfo->linux_uid, tlink);
-       radix_tree_tag_set(&cifs_sb->tlink_tree, pSesInfo->linux_uid,
-                          CIFS_TLINK_MASTER_TAG);
+       tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
        spin_unlock(&cifs_sb->tlink_tree_lock);
-       radix_tree_preload_end();
 
        queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
                                TLINK_IDLE_EXPIRE);
@@ -3107,32 +3100,25 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
 int
 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
 {
-       int i, ret;
+       struct rb_root *root = &cifs_sb->tlink_tree;
+       struct rb_node *node;
+       struct tcon_link *tlink;
        char *tmp;
-       struct tcon_link *tlink[8];
-       unsigned long index = 0;
 
        cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
 
-       do {
-               spin_lock(&cifs_sb->tlink_tree_lock);
-               ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree,
-                                            (void **)tlink, index,
-                                            ARRAY_SIZE(tlink));
-               /* increment index for next pass */
-               if (ret > 0)
-                       index = tlink[ret - 1]->tl_index + 1;
-               for (i = 0; i < ret; i++) {
-                       cifs_get_tlink(tlink[i]);
-                       clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags);
-                       radix_tree_delete(&cifs_sb->tlink_tree,
-                                                       tlink[i]->tl_index);
-               }
-               spin_unlock(&cifs_sb->tlink_tree_lock);
+       spin_lock(&cifs_sb->tlink_tree_lock);
+       while ((node = rb_first(root))) {
+               tlink = rb_entry(node, struct tcon_link, tl_rbnode);
+               cifs_get_tlink(tlink);
+               clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
+               rb_erase(node, root);
 
-               for (i = 0; i < ret; i++)
-                       cifs_put_tlink(tlink[i]);
-       } while (ret != 0);
+               spin_unlock(&cifs_sb->tlink_tree_lock);
+               cifs_put_tlink(tlink);
+               spin_lock(&cifs_sb->tlink_tree_lock);
+       }
+       spin_unlock(&cifs_sb->tlink_tree_lock);
 
        tmp = cifs_sb->prepath;
        cifs_sb->prepathlen = 0;
@@ -3271,22 +3257,10 @@ out:
        return tcon;
 }
 
-static struct tcon_link *
+static inline struct tcon_link *
 cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb)
 {
-       struct tcon_link *tlink;
-       unsigned int ret;
-
-       spin_lock(&cifs_sb->tlink_tree_lock);
-       ret = radix_tree_gang_lookup_tag(&cifs_sb->tlink_tree, (void **)&tlink,
-                                       0, 1, CIFS_TLINK_MASTER_TAG);
-       spin_unlock(&cifs_sb->tlink_tree_lock);
-
-       /* the master tcon should always be present */
-       if (ret == 0)
-               BUG();
-
-       return tlink;
+       return cifs_sb->master_tlink;
 }
 
 struct cifsTconInfo *
@@ -3302,6 +3276,47 @@ cifs_sb_tcon_pending_wait(void *unused)
        return signal_pending(current) ? -ERESTARTSYS : 0;
 }
 
+/* find and return a tlink with given uid */
+static struct tcon_link *
+tlink_rb_search(struct rb_root *root, uid_t uid)
+{
+       struct rb_node *node = root->rb_node;
+       struct tcon_link *tlink;
+
+       while (node) {
+               tlink = rb_entry(node, struct tcon_link, tl_rbnode);
+
+               if (tlink->tl_uid > uid)
+                       node = node->rb_left;
+               else if (tlink->tl_uid < uid)
+                       node = node->rb_right;
+               else
+                       return tlink;
+       }
+       return NULL;
+}
+
+/* insert a tcon_link into the tree */
+static void
+tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink)
+{
+       struct rb_node **new = &(root->rb_node), *parent = NULL;
+       struct tcon_link *tlink;
+
+       while (*new) {
+               tlink = rb_entry(*new, struct tcon_link, tl_rbnode);
+               parent = *new;
+
+               if (tlink->tl_uid > new_tlink->tl_uid)
+                       new = &((*new)->rb_left);
+               else
+                       new = &((*new)->rb_right);
+       }
+
+       rb_link_node(&new_tlink->tl_rbnode, parent, new);
+       rb_insert_color(&new_tlink->tl_rbnode, root);
+}
+
 /*
  * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the
  * current task.
@@ -3309,7 +3324,7 @@ cifs_sb_tcon_pending_wait(void *unused)
  * If the superblock doesn't refer to a multiuser mount, then just return
  * the master tcon for the mount.
  *
- * First, search the radix tree for an existing tcon for this fsuid. If one
+ * First, search the rbtree for an existing tcon for this fsuid. If one
  * exists, then check to see if it's pending construction. If it is then wait
  * for construction to complete. Once it's no longer pending, check to see if
  * it failed and either return an error or retry construction, depending on
@@ -3322,14 +3337,14 @@ struct tcon_link *
 cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
 {
        int ret;
-       unsigned long fsuid = (unsigned long) current_fsuid();
+       uid_t fsuid = current_fsuid();
        struct tcon_link *tlink, *newtlink;
 
        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
                return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
 
        spin_lock(&cifs_sb->tlink_tree_lock);
-       tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid);
+       tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
        if (tlink)
                cifs_get_tlink(tlink);
        spin_unlock(&cifs_sb->tlink_tree_lock);
@@ -3338,36 +3353,24 @@ cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
                newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
                if (newtlink == NULL)
                        return ERR_PTR(-ENOMEM);
-               newtlink->tl_index = fsuid;
+               newtlink->tl_uid = fsuid;
                newtlink->tl_tcon = ERR_PTR(-EACCES);
                set_bit(TCON_LINK_PENDING, &newtlink->tl_flags);
                set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags);
                cifs_get_tlink(newtlink);
 
-               ret = radix_tree_preload(GFP_KERNEL);
-               if (ret != 0) {
-                       kfree(newtlink);
-                       return ERR_PTR(ret);
-               }
-
                spin_lock(&cifs_sb->tlink_tree_lock);
                /* was one inserted after previous search? */
-               tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid);
+               tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
                if (tlink) {
                        cifs_get_tlink(tlink);
                        spin_unlock(&cifs_sb->tlink_tree_lock);
-                       radix_tree_preload_end();
                        kfree(newtlink);
                        goto wait_for_construction;
                }
-               ret = radix_tree_insert(&cifs_sb->tlink_tree, fsuid, newtlink);
-               spin_unlock(&cifs_sb->tlink_tree_lock);
-               radix_tree_preload_end();
-               if (ret) {
-                       kfree(newtlink);
-                       return ERR_PTR(ret);
-               }
                tlink = newtlink;
+               tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
+               spin_unlock(&cifs_sb->tlink_tree_lock);
        } else {
 wait_for_construction:
                ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING,
@@ -3413,39 +3416,39 @@ cifs_prune_tlinks(struct work_struct *work)
 {
        struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info,
                                                    prune_tlinks.work);
-       struct tcon_link *tlink[8];
-       unsigned long now = jiffies;
-       unsigned long index = 0;
-       int i, ret;
+       struct rb_root *root = &cifs_sb->tlink_tree;
+       struct rb_node *node = rb_first(root);
+       struct rb_node *tmp;
+       struct tcon_link *tlink;
 
-       do {
-               spin_lock(&cifs_sb->tlink_tree_lock);
-               ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree,
-                                            (void **)tlink, index,
-                                            ARRAY_SIZE(tlink));
-               /* increment index for next pass */
-               if (ret > 0)
-                       index = tlink[ret - 1]->tl_index + 1;
-               for (i = 0; i < ret; i++) {
-                       if (test_bit(TCON_LINK_MASTER, &tlink[i]->tl_flags) ||
-                           atomic_read(&tlink[i]->tl_count) != 0 ||
-                           time_after(tlink[i]->tl_time + TLINK_IDLE_EXPIRE,
-                                      now)) {
-                               tlink[i] = NULL;
-                               continue;
-                       }
-                       cifs_get_tlink(tlink[i]);
-                       clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags);
-                       radix_tree_delete(&cifs_sb->tlink_tree,
-                                         tlink[i]->tl_index);
-               }
-               spin_unlock(&cifs_sb->tlink_tree_lock);
+       /*
+        * Because we drop the spinlock in the loop in order to put the tlink
+        * it's not guarded against removal of links from the tree. The only
+        * places that remove entries from the tree are this function and
+        * umounts. Because this function is non-reentrant and is canceled
+        * before umount can proceed, this is safe.
+        */
+       spin_lock(&cifs_sb->tlink_tree_lock);
+       node = rb_first(root);
+       while (node != NULL) {
+               tmp = node;
+               node = rb_next(tmp);
+               tlink = rb_entry(tmp, struct tcon_link, tl_rbnode);
+
+               if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) ||
+                   atomic_read(&tlink->tl_count) != 0 ||
+                   time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies))
+                       continue;
 
-               for (i = 0; i < ret; i++) {
-                       if (tlink[i] != NULL)
-                               cifs_put_tlink(tlink[i]);
-               }
-       } while (ret != 0);
+               cifs_get_tlink(tlink);
+               clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
+               rb_erase(tmp, root);
+
+               spin_unlock(&cifs_sb->tlink_tree_lock);
+               cifs_put_tlink(tlink);
+               spin_lock(&cifs_sb->tlink_tree_lock);
+       }
+       spin_unlock(&cifs_sb->tlink_tree_lock);
 
        queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
                                TLINK_IDLE_EXPIRE);
index ae82159cf7fa6921bb3a27a1fc5e56fbb1045a5c..06c3e83fa387fecf63b93e33a0455dac6da45f6d 100644 (file)
@@ -146,12 +146,7 @@ client_can_cache:
                rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
                                         xid, NULL);
 
-       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-               pCifsInode->clientCanCacheAll = true;
-               pCifsInode->clientCanCacheRead = true;
-               cFYI(1, "Exclusive Oplock granted on inode %p", inode);
-       } else if ((oplock & 0xF) == OPLOCK_READ)
-               pCifsInode->clientCanCacheRead = true;
+       cifs_set_oplock_level(pCifsInode, oplock);
 
        return rc;
 }
@@ -253,12 +248,7 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
                list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
        spin_unlock(&cifs_file_list_lock);
 
-       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-               pCifsInode->clientCanCacheAll = true;
-               pCifsInode->clientCanCacheRead = true;
-               cFYI(1, "Exclusive Oplock inode %p", inode);
-       } else if ((oplock & 0xF) == OPLOCK_READ)
-               pCifsInode->clientCanCacheRead = true;
+       cifs_set_oplock_level(pCifsInode, oplock);
 
        file->private_data = pCifsFile;
        return pCifsFile;
@@ -271,8 +261,9 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
  */
 void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
 {
+       struct inode *inode = cifs_file->dentry->d_inode;
        struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink);
-       struct cifsInodeInfo *cifsi = CIFS_I(cifs_file->dentry->d_inode);
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
        struct cifsLockInfo *li, *tmp;
 
        spin_lock(&cifs_file_list_lock);
@@ -288,8 +279,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
        if (list_empty(&cifsi->openFileList)) {
                cFYI(1, "closing last open instance for inode %p",
                        cifs_file->dentry->d_inode);
-               cifsi->clientCanCacheRead = false;
-               cifsi->clientCanCacheAll  = false;
+               cifs_set_oplock_level(cifsi, 0);
        }
        spin_unlock(&cifs_file_list_lock);
 
@@ -607,8 +597,6 @@ reopen_success:
                rc = filemap_write_and_wait(inode->i_mapping);
                mapping_set_error(inode->i_mapping, rc);
 
-               pCifsInode->clientCanCacheAll = false;
-               pCifsInode->clientCanCacheRead = false;
                if (tcon->unix_ext)
                        rc = cifs_get_inode_info_unix(&inode,
                                full_path, inode->i_sb, xid);
@@ -622,18 +610,9 @@ reopen_success:
             invalidate the current end of file on the server
             we can not go to the server to get the new inod
             info */
-       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-               pCifsInode->clientCanCacheAll = true;
-               pCifsInode->clientCanCacheRead = true;
-               cFYI(1, "Exclusive Oplock granted on inode %p",
-                        pCifsFile->dentry->d_inode);
-       } else if ((oplock & 0xF) == OPLOCK_READ) {
-               pCifsInode->clientCanCacheRead = true;
-               pCifsInode->clientCanCacheAll = false;
-       } else {
-               pCifsInode->clientCanCacheRead = false;
-               pCifsInode->clientCanCacheAll = false;
-       }
+
+       cifs_set_oplock_level(pCifsInode, oplock);
+
        cifs_relock_file(pCifsFile);
 
 reopen_error_exit:
@@ -775,12 +754,6 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
        tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink);
-
-       if (file->private_data == NULL) {
-               rc = -EBADF;
-               FreeXid(xid);
-               return rc;
-       }
        netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
 
        if ((tcon->ses->capabilities & CAP_UNIX) &&
@@ -956,6 +929,7 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
 ssize_t cifs_user_write(struct file *file, const char __user *write_data,
        size_t write_size, loff_t *poffset)
 {
+       struct inode *inode = file->f_path.dentry->d_inode;
        int rc = 0;
        unsigned int bytes_written = 0;
        unsigned int total_written;
@@ -963,7 +937,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
        struct cifsTconInfo *pTcon;
        int xid, long_op;
        struct cifsFileInfo *open_file;
-       struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
 
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 
@@ -1029,21 +1003,17 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
 
        cifs_stats_bytes_written(pTcon, total_written);
 
-       /* since the write may have blocked check these pointers again */
-       if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
-               struct inode *inode = file->f_path.dentry->d_inode;
 /* Do not update local mtime - server will set its actual value on write
- *             inode->i_ctime = inode->i_mtime =
- *                     current_fs_time(inode->i_sb);*/
-               if (total_written > 0) {
-                       spin_lock(&inode->i_lock);
-                       if (*poffset > file->f_path.dentry->d_inode->i_size)
-                               i_size_write(file->f_path.dentry->d_inode,
-                                       *poffset);
-                       spin_unlock(&inode->i_lock);
-               }
-               mark_inode_dirty_sync(file->f_path.dentry->d_inode);
+ *     inode->i_ctime = inode->i_mtime =
+ *             current_fs_time(inode->i_sb);*/
+       if (total_written > 0) {
+               spin_lock(&inode->i_lock);
+               if (*poffset > inode->i_size)
+                       i_size_write(inode, *poffset);
+               spin_unlock(&inode->i_lock);
        }
+       mark_inode_dirty_sync(inode);
+
        FreeXid(xid);
        return total_written;
 }
@@ -1178,7 +1148,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
                                        bool fsuid_only)
 {
        struct cifsFileInfo *open_file;
-       struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
+       struct cifs_sb_info *cifs_sb;
        bool any_available = false;
        int rc;
 
@@ -1192,6 +1162,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
                return NULL;
        }
 
+       cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
+
        /* only filter by fsuid on multiuser mounts */
        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
                fsuid_only = false;
index 077bf756f34231300c6b0d7fdae7cedf6023bd08..2fa22f20cfc500060991205e115995d2aa0253f3 100644 (file)
@@ -63,8 +63,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 #ifdef CONFIG_CIFS_POSIX
                case FS_IOC_GETFLAGS:
                        if (CIFS_UNIX_EXTATTR_CAP & caps) {
-                               if (pSMBFile == NULL)
-                                       break;
                                rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
                                        &ExtAttrBits, &ExtAttrMask);
                                if (rc == 0)
@@ -80,8 +78,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
                                        rc = -EFAULT;
                                        break;
                                }
-                               if (pSMBFile == NULL)
-                                       break;
                                /* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid,
                                        extAttrBits, &ExtAttrMask);*/
                        }
index c4e296fe351876252a48210f81f6cbae165562f8..43f10281bc19e80be48303e1bd9c974b4882cb37 100644 (file)
@@ -569,10 +569,9 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
 
                                cFYI(1, "file id match, oplock break");
                                pCifsInode = CIFS_I(netfile->dentry->d_inode);
-                               pCifsInode->clientCanCacheAll = false;
-                               if (pSMB->OplockLevel == 0)
-                                       pCifsInode->clientCanCacheRead = false;
 
+                               cifs_set_oplock_level(pCifsInode,
+                                                     pSMB->OplockLevel);
                                /*
                                 * cifs_oplock_break_put() can't be called
                                 * from here.  Get reference after queueing
@@ -722,3 +721,23 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
                           cifs_sb_master_tcon(cifs_sb)->treeName);
        }
 }
+
+void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
+{
+       oplock &= 0xF;
+
+       if (oplock == OPLOCK_EXCLUSIVE) {
+               cinode->clientCanCacheAll = true;
+               cinode->clientCanCacheRead = true;
+               cFYI(1, "Exclusive Oplock granted on inode %p",
+                    &cinode->vfs_inode);
+       } else if (oplock == OPLOCK_READ) {
+               cinode->clientCanCacheAll = false;
+               cinode->clientCanCacheRead = true;
+               cFYI(1, "Level II Oplock granted on inode %p",
+                   &cinode->vfs_inode);
+       } else {
+               cinode->clientCanCacheAll = false;
+               cinode->clientCanCacheRead = false;
+       }
+}
index 8b5dd6369f82c19d5ba28dea07018e4fb13a025f..6a5edea2d70b3ac7c56e8b272686b5a799eabbcf 100644 (file)
@@ -177,7 +177,7 @@ struct mpage_da_data {
 
 struct ext4_io_page {
        struct page     *p_page;
-       int             p_count;
+       atomic_t        p_count;
 };
 
 #define MAX_IO_PAGES 128
@@ -858,6 +858,7 @@ struct ext4_inode_info {
        spinlock_t i_completed_io_lock;
        /* current io_end structure for async DIO write*/
        ext4_io_end_t *cur_aio_dio;
+       atomic_t i_ioend_count; /* Number of outstanding io_end structs */
 
        /*
         * Transactions that contain inode's metadata needed to complete
@@ -2060,6 +2061,7 @@ extern int ext4_move_extents(struct file *o_filp, struct file *d_filp,
 /* page-io.c */
 extern int __init ext4_init_pageio(void);
 extern void ext4_exit_pageio(void);
+extern void ext4_ioend_wait(struct inode *);
 extern void ext4_free_io_end(ext4_io_end_t *io);
 extern ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags);
 extern int ext4_end_io_nolock(ext4_io_end_t *io);
index 1916164704667dc3c190ab327781933fa7c5f4b8..bdbe69902207c151df025d98690c4c016cf0b0e9 100644 (file)
@@ -53,6 +53,7 @@
 static inline int ext4_begin_ordered_truncate(struct inode *inode,
                                              loff_t new_size)
 {
+       trace_ext4_begin_ordered_truncate(inode, new_size);
        return jbd2_journal_begin_ordered_truncate(
                                        EXT4_SB(inode->i_sb)->s_journal,
                                        &EXT4_I(inode)->jinode,
@@ -178,6 +179,7 @@ void ext4_evict_inode(struct inode *inode)
        handle_t *handle;
        int err;
 
+       trace_ext4_evict_inode(inode);
        if (inode->i_nlink) {
                truncate_inode_pages(&inode->i_data, 0);
                goto no_delete;
@@ -5410,9 +5412,7 @@ int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
         * will return the blocks that include the delayed allocation
         * blocks for this file.
         */
-       spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
        delalloc_blocks = EXT4_I(inode)->i_reserved_data_blocks;
-       spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
 
        stat->blocks += (delalloc_blocks << inode->i_sb->s_blocksize_bits)>>9;
        return 0;
@@ -5649,6 +5649,7 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
        int err, ret;
 
        might_sleep();
+       trace_ext4_mark_inode_dirty(inode, _RET_IP_);
        err = ext4_reserve_inode_write(handle, inode, &iloc);
        if (ext4_handle_valid(handle) &&
            EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize &&
index c58eba34724a4281f1cb8bb405ab607ef09b49ff..5b4d4e3a4d58e3506c15e891e7b8df394bc0838f 100644 (file)
@@ -4640,8 +4640,6 @@ do_more:
                 * with group lock held. generate_buddy look at
                 * them with group lock_held
                 */
-               if (test_opt(sb, DISCARD))
-                       ext4_issue_discard(sb, block_group, bit, count);
                ext4_lock_group(sb, block_group);
                mb_clear_bits(bitmap_bh->b_data, bit, count);
                mb_free_blocks(inode, &e4b, bit, count);
index 46a7d6a9d9764b82075071c94f661cc65c3675fc..7f5451cd1d38bff2399471750618fc7429ce5c5e 100644 (file)
 
 static struct kmem_cache *io_page_cachep, *io_end_cachep;
 
+#define WQ_HASH_SZ             37
+#define to_ioend_wq(v) (&ioend_wq[((unsigned long)v) % WQ_HASH_SZ])
+static wait_queue_head_t ioend_wq[WQ_HASH_SZ];
+
 int __init ext4_init_pageio(void)
 {
+       int i;
+
        io_page_cachep = KMEM_CACHE(ext4_io_page, SLAB_RECLAIM_ACCOUNT);
        if (io_page_cachep == NULL)
                return -ENOMEM;
@@ -42,6 +48,8 @@ int __init ext4_init_pageio(void)
                kmem_cache_destroy(io_page_cachep);
                return -ENOMEM;
        }
+       for (i = 0; i < WQ_HASH_SZ; i++)
+               init_waitqueue_head(&ioend_wq[i]);
 
        return 0;
 }
@@ -52,24 +60,37 @@ void ext4_exit_pageio(void)
        kmem_cache_destroy(io_page_cachep);
 }
 
+void ext4_ioend_wait(struct inode *inode)
+{
+       wait_queue_head_t *wq = to_ioend_wq(inode);
+
+       wait_event(*wq, (atomic_read(&EXT4_I(inode)->i_ioend_count) == 0));
+}
+
+static void put_io_page(struct ext4_io_page *io_page)
+{
+       if (atomic_dec_and_test(&io_page->p_count)) {
+               end_page_writeback(io_page->p_page);
+               put_page(io_page->p_page);
+               kmem_cache_free(io_page_cachep, io_page);
+       }
+}
+
 void ext4_free_io_end(ext4_io_end_t *io)
 {
        int i;
+       wait_queue_head_t *wq;
 
        BUG_ON(!io);
        if (io->page)
                put_page(io->page);
-       for (i = 0; i < io->num_io_pages; i++) {
-               if (--io->pages[i]->p_count == 0) {
-                       struct page *page = io->pages[i]->p_page;
-
-                       end_page_writeback(page);
-                       put_page(page);
-                       kmem_cache_free(io_page_cachep, io->pages[i]);
-               }
-       }
+       for (i = 0; i < io->num_io_pages; i++)
+               put_io_page(io->pages[i]);
        io->num_io_pages = 0;
-       iput(io->inode);
+       wq = to_ioend_wq(io->inode);
+       if (atomic_dec_and_test(&EXT4_I(io->inode)->i_ioend_count) &&
+           waitqueue_active(wq))
+               wake_up_all(wq);
        kmem_cache_free(io_end_cachep, io);
 }
 
@@ -142,8 +163,8 @@ ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags)
        io = kmem_cache_alloc(io_end_cachep, flags);
        if (io) {
                memset(io, 0, sizeof(*io));
-               io->inode = igrab(inode);
-               BUG_ON(!io->inode);
+               atomic_inc(&EXT4_I(inode)->i_ioend_count);
+               io->inode = inode;
                INIT_WORK(&io->work, ext4_end_io_work);
                INIT_LIST_HEAD(&io->list);
        }
@@ -171,35 +192,15 @@ static void ext4_end_bio(struct bio *bio, int error)
        struct workqueue_struct *wq;
        struct inode *inode;
        unsigned long flags;
-       ext4_fsblk_t err_block;
        int i;
 
        BUG_ON(!io_end);
-       inode = io_end->inode;
        bio->bi_private = NULL;
        bio->bi_end_io = NULL;
        if (test_bit(BIO_UPTODATE, &bio->bi_flags))
                error = 0;
-       err_block = bio->bi_sector >> (inode->i_blkbits - 9);
        bio_put(bio);
 
-       if (!(inode->i_sb->s_flags & MS_ACTIVE)) {
-               pr_err("sb umounted, discard end_io request for inode %lu\n",
-                       io_end->inode->i_ino);
-               ext4_free_io_end(io_end);
-               return;
-       }
-
-       if (error) {
-               io_end->flag |= EXT4_IO_END_ERROR;
-               ext4_warning(inode->i_sb, "I/O error writing to inode %lu "
-                            "(offset %llu size %ld starting block %llu)",
-                            inode->i_ino,
-                            (unsigned long long) io_end->offset,
-                            (long) io_end->size,
-                            (unsigned long long) err_block);
-       }
-
        for (i = 0; i < io_end->num_io_pages; i++) {
                struct page *page = io_end->pages[i]->p_page;
                struct buffer_head *bh, *head;
@@ -236,13 +237,7 @@ static void ext4_end_bio(struct bio *bio, int error)
                        } while (bh != head);
                }
 
-               if (--io_end->pages[i]->p_count == 0) {
-                       struct page *page = io_end->pages[i]->p_page;
-
-                       end_page_writeback(page);
-                       put_page(page);
-                       kmem_cache_free(io_page_cachep, io_end->pages[i]);
-               }
+               put_io_page(io_end->pages[i]);
 
                /*
                 * If this is a partial write which happened to make
@@ -254,8 +249,19 @@ static void ext4_end_bio(struct bio *bio, int error)
                if (!partial_write)
                        SetPageUptodate(page);
        }
-
        io_end->num_io_pages = 0;
+       inode = io_end->inode;
+
+       if (error) {
+               io_end->flag |= EXT4_IO_END_ERROR;
+               ext4_warning(inode->i_sb, "I/O error writing to inode %lu "
+                            "(offset %llu size %ld starting block %llu)",
+                            inode->i_ino,
+                            (unsigned long long) io_end->offset,
+                            (long) io_end->size,
+                            (unsigned long long)
+                            bio->bi_sector >> (inode->i_blkbits - 9));
+       }
 
        /* Add the io_end to per-inode completed io list*/
        spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags);
@@ -305,7 +311,6 @@ static int io_submit_init(struct ext4_io_submit *io,
        bio->bi_private = io->io_end = io_end;
        bio->bi_end_io = ext4_end_bio;
 
-       io_end->inode = inode;
        io_end->offset = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh);
 
        io->io_bio = bio;
@@ -360,7 +365,7 @@ submit_and_retry:
        if ((io_end->num_io_pages == 0) ||
            (io_end->pages[io_end->num_io_pages-1] != io_page)) {
                io_end->pages[io_end->num_io_pages++] = io_page;
-               io_page->p_count++;
+               atomic_inc(&io_page->p_count);
        }
        return 0;
 }
@@ -389,7 +394,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
                return -ENOMEM;
        }
        io_page->p_page = page;
-       io_page->p_count = 0;
+       atomic_set(&io_page->p_count, 1);
        get_page(page);
 
        for (bh = head = page_buffers(page), block_start = 0;
@@ -421,10 +426,6 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
         * PageWriteback bit from the page to prevent the system from
         * wedging later on.
         */
-       if (io_page->p_count == 0) {
-               put_page(page);
-               end_page_writeback(page);
-               kmem_cache_free(io_page_cachep, io_page);
-       }
+       put_io_page(io_page);
        return ret;
 }
index 40131b777af66c3112bb1df16265faadac435d0f..61182fe6254e94ad606a6c67fed1b30ef289ad38 100644 (file)
@@ -828,12 +828,22 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
        ei->cur_aio_dio = NULL;
        ei->i_sync_tid = 0;
        ei->i_datasync_tid = 0;
+       atomic_set(&ei->i_ioend_count, 0);
 
        return &ei->vfs_inode;
 }
 
+static int ext4_drop_inode(struct inode *inode)
+{
+       int drop = generic_drop_inode(inode);
+
+       trace_ext4_drop_inode(inode, drop);
+       return drop;
+}
+
 static void ext4_destroy_inode(struct inode *inode)
 {
+       ext4_ioend_wait(inode);
        if (!list_empty(&(EXT4_I(inode)->i_orphan))) {
                ext4_msg(inode->i_sb, KERN_ERR,
                         "Inode %lu (%p): orphan list check failed!",
@@ -1173,6 +1183,7 @@ static const struct super_operations ext4_sops = {
        .destroy_inode  = ext4_destroy_inode,
        .write_inode    = ext4_write_inode,
        .dirty_inode    = ext4_dirty_inode,
+       .drop_inode     = ext4_drop_inode,
        .evict_inode    = ext4_evict_inode,
        .put_super      = ext4_put_super,
        .sync_fs        = ext4_sync_fs,
@@ -1194,6 +1205,7 @@ static const struct super_operations ext4_nojournal_sops = {
        .destroy_inode  = ext4_destroy_inode,
        .write_inode    = ext4_write_inode,
        .dirty_inode    = ext4_dirty_inode,
+       .drop_inode     = ext4_drop_inode,
        .evict_inode    = ext4_evict_inode,
        .write_super    = ext4_write_super,
        .put_super      = ext4_put_super,
@@ -2699,7 +2711,6 @@ static int ext4_lazyinit_thread(void *arg)
        struct ext4_li_request *elr;
        unsigned long next_wakeup;
        DEFINE_WAIT(wait);
-       int ret;
 
        BUG_ON(NULL == eli);
 
@@ -2723,13 +2734,12 @@ cont_thread:
                        elr = list_entry(pos, struct ext4_li_request,
                                         lr_request);
 
-                       if (time_after_eq(jiffies, elr->lr_next_sched))
-                               ret = ext4_run_li_request(elr);
-
-                       if (ret) {
-                               ret = 0;
-                               ext4_remove_li_request(elr);
-                               continue;
+                       if (time_after_eq(jiffies, elr->lr_next_sched)) {
+                               if (ext4_run_li_request(elr) != 0) {
+                                       /* error, remove the lazy_init job */
+                                       ext4_remove_li_request(elr);
+                                       continue;
+                               }
                        }
 
                        if (time_before(elr->lr_next_sched, next_wakeup))
@@ -2740,7 +2750,8 @@ cont_thread:
                if (freezing(current))
                        refrigerator();
 
-               if (time_after_eq(jiffies, next_wakeup)) {
+               if ((time_after_eq(jiffies, next_wakeup)) ||
+                   (MAX_JIFFY_OFFSET == next_wakeup)) {
                        cond_resched();
                        continue;
                }
@@ -3348,6 +3359,24 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        get_random_bytes(&sbi->s_next_generation, sizeof(u32));
        spin_lock_init(&sbi->s_next_gen_lock);
 
+       err = percpu_counter_init(&sbi->s_freeblocks_counter,
+                       ext4_count_free_blocks(sb));
+       if (!err) {
+               err = percpu_counter_init(&sbi->s_freeinodes_counter,
+                               ext4_count_free_inodes(sb));
+       }
+       if (!err) {
+               err = percpu_counter_init(&sbi->s_dirs_counter,
+                               ext4_count_dirs(sb));
+       }
+       if (!err) {
+               err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0);
+       }
+       if (err) {
+               ext4_msg(sb, KERN_ERR, "insufficient memory");
+               goto failed_mount3;
+       }
+
        sbi->s_stripe = ext4_get_stripe_size(sbi);
        sbi->s_max_writeback_mb_bump = 128;
 
@@ -3446,22 +3475,19 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
        set_task_ioprio(sbi->s_journal->j_task, journal_ioprio);
 
-no_journal:
-       err = percpu_counter_init(&sbi->s_freeblocks_counter,
-                                 ext4_count_free_blocks(sb));
-       if (!err)
-               err = percpu_counter_init(&sbi->s_freeinodes_counter,
-                                         ext4_count_free_inodes(sb));
-       if (!err)
-               err = percpu_counter_init(&sbi->s_dirs_counter,
-                                         ext4_count_dirs(sb));
-       if (!err)
-               err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0);
-       if (err) {
-               ext4_msg(sb, KERN_ERR, "insufficient memory");
-               goto failed_mount_wq;
-       }
+       /*
+        * The journal may have updated the bg summary counts, so we
+        * need to update the global counters.
+        */
+       percpu_counter_set(&sbi->s_freeblocks_counter,
+                          ext4_count_free_blocks(sb));
+       percpu_counter_set(&sbi->s_freeinodes_counter,
+                          ext4_count_free_inodes(sb));
+       percpu_counter_set(&sbi->s_dirs_counter,
+                          ext4_count_dirs(sb));
+       percpu_counter_set(&sbi->s_dirtyblocks_counter, 0);
 
+no_journal:
        EXT4_SB(sb)->dio_unwritten_wq = create_workqueue("ext4-dio-unwritten");
        if (!EXT4_SB(sb)->dio_unwritten_wq) {
                printk(KERN_ERR "EXT4-fs: failed to create DIO workqueue\n");
@@ -3611,10 +3637,6 @@ failed_mount_wq:
                jbd2_journal_destroy(sbi->s_journal);
                sbi->s_journal = NULL;
        }
-       percpu_counter_destroy(&sbi->s_freeblocks_counter);
-       percpu_counter_destroy(&sbi->s_freeinodes_counter);
-       percpu_counter_destroy(&sbi->s_dirs_counter);
-       percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
 failed_mount3:
        if (sbi->s_flex_groups) {
                if (is_vmalloc_addr(sbi->s_flex_groups))
@@ -3622,6 +3644,10 @@ failed_mount3:
                else
                        kfree(sbi->s_flex_groups);
        }
+       percpu_counter_destroy(&sbi->s_freeblocks_counter);
+       percpu_counter_destroy(&sbi->s_freeinodes_counter);
+       percpu_counter_destroy(&sbi->s_dirs_counter);
+       percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
 failed_mount2:
        for (i = 0; i < db_count; i++)
                brelse(sbi->s_group_desc[i]);
@@ -3949,13 +3975,11 @@ static int ext4_commit_super(struct super_block *sb, int sync)
        else
                es->s_kbytes_written =
                        cpu_to_le64(EXT4_SB(sb)->s_kbytes_written);
-       if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeblocks_counter))
-               ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
-                                       &EXT4_SB(sb)->s_freeblocks_counter));
-       if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeinodes_counter))
-               es->s_free_inodes_count =
-                       cpu_to_le32(percpu_counter_sum_positive(
-                                       &EXT4_SB(sb)->s_freeinodes_counter));
+       ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
+                                          &EXT4_SB(sb)->s_freeblocks_counter));
+       es->s_free_inodes_count =
+               cpu_to_le32(percpu_counter_sum_positive(
+                               &EXT4_SB(sb)->s_freeinodes_counter));
        sb->s_dirt = 0;
        BUFFER_TRACE(sbh, "marking dirty");
        mark_buffer_dirty(sbh);
@@ -4556,12 +4580,10 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
 
 static int ext4_quota_off(struct super_block *sb, int type)
 {
-       /* Force all delayed allocation blocks to be allocated */
-       if (test_opt(sb, DELALLOC)) {
-               down_read(&sb->s_umount);
+       /* Force all delayed allocation blocks to be allocated.
+        * Caller already holds s_umount sem */
+       if (test_opt(sb, DELALLOC))
                sync_filesystem(sb);
-               up_read(&sb->s_umount);
-       }
 
        return dquot_quota_off(sb, type);
 }
index ac943c1307b5e33272f2d91d07f95c6a332f3e7a..aa996471ec5c961d7d94c62c10a20d29ac8e1bbb 100644 (file)
@@ -629,8 +629,6 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
 
 static int gfs2_setlease(struct file *file, long arg, struct file_lock **fl)
 {
-       if (arg != F_UNLCK)
-               locks_free_lock(*fl);
        return -EINVAL;
 }
 
index eac5f96323e3d9640a197ee5eb10acdbf6046591..793cb9d943d21a70584958c27fba6b2f97b37f93 100644 (file)
@@ -14,7 +14,7 @@ void hpfs_lock_creation(struct super_block *s)
 #ifdef DEBUG_LOCKS
        printk("lock creation\n");
 #endif
-       down(&hpfs_sb(s)->hpfs_creation_de);
+       mutex_lock(&hpfs_sb(s)->hpfs_creation_de);
 }
 
 void hpfs_unlock_creation(struct super_block *s)
@@ -22,7 +22,7 @@ void hpfs_unlock_creation(struct super_block *s)
 #ifdef DEBUG_LOCKS
        printk("unlock creation\n");
 #endif
-       up(&hpfs_sb(s)->hpfs_creation_de);
+       mutex_unlock(&hpfs_sb(s)->hpfs_creation_de);
 }
 
 /* Map a sector into a buffer and return pointers to it and to the buffer. */
index b59eac0232a0f057063fac03d747a8b627560056..2fee17d0d9ab37ac67602007b0ab556f9e9eb22d 100644 (file)
@@ -87,7 +87,7 @@ struct hpfs_sb_info {
        unsigned *sb_bmp_dir;           /* main bitmap directory */
        unsigned sb_c_bitmap;           /* current bitmap */
        unsigned sb_max_fwd_alloc;      /* max forwad allocation */
-       struct semaphore hpfs_creation_de; /* when creating dirents, nobody else
+       struct mutex hpfs_creation_de;  /* when creating dirents, nobody else
                                           can alloc blocks */
        /*unsigned sb_mounting : 1;*/
        int sb_timeshift;
index bb69389972eb33148dfdc4176ea87b7003cb39f0..6c5f01597c3af07a21ec162b996437545c6e13af 100644 (file)
@@ -491,7 +491,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
        sbi->sb_bmp_dir = NULL;
        sbi->sb_cp_table = NULL;
 
-       init_MUTEX(&sbi->hpfs_creation_de);
+       mutex_init(&sbi->hpfs_creation_de);
 
        uid = current_uid();
        gid = current_gid();
index 538417c1fdbbcbb630cbcdb885c74ebe5f433844..c590d155c0959bfbe1f8ce2f6be9702afd2904f4 100644 (file)
@@ -1838,7 +1838,6 @@ size_t journal_tag_bytes(journal_t *journal)
  */
 #define JBD2_MAX_SLABS 8
 static struct kmem_cache *jbd2_slab[JBD2_MAX_SLABS];
-static DECLARE_MUTEX(jbd2_slab_create_sem);
 
 static const char *jbd2_slab_names[JBD2_MAX_SLABS] = {
        "jbd2_1k", "jbd2_2k", "jbd2_4k", "jbd2_8k",
@@ -1859,6 +1858,7 @@ static void jbd2_journal_destroy_slabs(void)
 
 static int jbd2_journal_create_slab(size_t size)
 {
+       static DEFINE_MUTEX(jbd2_slab_create_mutex);
        int i = order_base_2(size) - 10;
        size_t slab_size;
 
@@ -1870,16 +1870,16 @@ static int jbd2_journal_create_slab(size_t size)
 
        if (unlikely(i < 0))
                i = 0;
-       down(&jbd2_slab_create_sem);
+       mutex_lock(&jbd2_slab_create_mutex);
        if (jbd2_slab[i]) {
-               up(&jbd2_slab_create_sem);
+               mutex_unlock(&jbd2_slab_create_mutex);
                return 0;       /* Already created */
        }
 
        slab_size = 1 << (i+10);
        jbd2_slab[i] = kmem_cache_create(jbd2_slab_names[i], slab_size,
                                         slab_size, 0, NULL);
-       up(&jbd2_slab_create_sem);
+       mutex_unlock(&jbd2_slab_create_mutex);
        if (!jbd2_slab[i]) {
                printk(KERN_EMERG "JBD2: no memory for jbd2_slab cache\n");
                return -ENOMEM;
index 5b526a9778828977871d01e610fdfd797da0527a..65765cb6afedaee442c1e1ab21bf7269ce9b07c7 100644 (file)
@@ -235,11 +235,8 @@ static void locks_copy_private(struct file_lock *new, struct file_lock *fl)
                        fl->fl_ops->fl_copy_lock(new, fl);
                new->fl_ops = fl->fl_ops;
        }
-       if (fl->fl_lmops) {
-               if (fl->fl_lmops->fl_copy_lock)
-                       fl->fl_lmops->fl_copy_lock(new, fl);
+       if (fl->fl_lmops)
                new->fl_lmops = fl->fl_lmops;
-       }
 }
 
 /*
@@ -1428,8 +1425,9 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
                goto out;
 
        if (my_before != NULL) {
-               *flp = *my_before;
                error = lease->fl_lmops->fl_change(my_before, arg);
+               if (!error)
+                       *flp = *my_before;
                goto out;
        }
 
@@ -1444,8 +1442,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
        return 0;
 
 out:
-       if (arg != F_UNLCK)
-               locks_free_lock(lease);
        return error;
 }
 EXPORT_SYMBOL(generic_setlease);
@@ -1524,8 +1520,11 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
        }
        lock_flocks();
        error = __vfs_setlease(filp, arg, &fl);
-       if (error)
-               goto out_unlock;
+       if (error) {
+               unlock_flocks();
+               locks_free_lock(fl);
+               goto out_free_fasync;
+       }
 
        /*
         * fasync_insert_entry() returns the old entry if any.
@@ -1541,12 +1540,12 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
                fl->fl_type = F_UNLCK | F_INPROGRESS;
                fl->fl_break_time = jiffies - 10;
                time_out_leases(inode);
-               goto out_unlock;
+       } else {
+               error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
        }
-
-       error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
-out_unlock:
        unlock_flocks();
+
+out_free_fasync:
        if (new)
                fasync_free(new);
        return error;
index cd51a36b37f0956bf7eafde8ced983d5ae437b05..57afd4a6fabbb992b0b08ea9bb5399071ea576c2 100644 (file)
@@ -486,7 +486,7 @@ static inline int logfs_get_sb_bdev(struct logfs_super *s,
 
 /* dev_mtd.c */
 #ifdef CONFIG_MTD
-int logfs_get_sb_mtd(struct logfs_super *s, int mtdnr)
+int logfs_get_sb_mtd(struct logfs_super *s, int mtdnr);
 #else
 static inline int logfs_get_sb_mtd(struct logfs_super *s, int mtdnr)
 {
index 1e524fb73ba56200be86a3675181c78d7bd02fde..60677f9f13110d1a98774595de819fddf2c0ccdf 100644 (file)
@@ -884,7 +884,5 @@ static int nfs_setlease(struct file *file, long arg, struct file_lock **fl)
        dprintk("NFS: setlease(%s/%s, arg=%ld)\n",
                        file->f_path.dentry->d_parent->d_name.name,
                        file->f_path.dentry->d_name.name, arg);
-       if (arg != F_UNLCK)
-               locks_free_lock(*fl);
        return -EINVAL;
 }
index b7f818b0580c2667698b4cd2c0c14e8376cfa789..f1e5ec6b5105fe46a1537df2041f9d114d222f8d 100644 (file)
@@ -2652,6 +2652,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
        if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) {
                dprintk("NFSD: setlease failed [%d], no delegation\n", status);
                dp->dl_flock = NULL;
+               locks_free_lock(fl);
                unhash_delegation(dp);
                flag = NFS4_OPEN_DELEGATE_NONE;
                goto out;
index 47e64170305d8f862e2f67d73420eb3e0a8ed9e4..bd8cad21998e0e41ac88435b55ae9f3d275c0283 100644 (file)
@@ -33,18 +33,18 @@ struct stat {
        int             st_blksize;     /* Optimal block size for I/O.  */
        int             __pad2;
        long            st_blocks;      /* Number 512-byte blocks allocated. */
-       int             st_atime;       /* Time of last access.  */
-       unsigned int    st_atime_nsec;
-       int             st_mtime;       /* Time of last modification.  */
-       unsigned int    st_mtime_nsec;
-       int             st_ctime;       /* Time of last status change.  */
-       unsigned int    st_ctime_nsec;
+       long            st_atime;       /* Time of last access.  */
+       unsigned long   st_atime_nsec;
+       long            st_mtime;       /* Time of last modification.  */
+       unsigned long   st_mtime_nsec;
+       long            st_ctime;       /* Time of last status change.  */
+       unsigned long   st_ctime_nsec;
        unsigned int    __unused4;
        unsigned int    __unused5;
 };
 
-#if __BITS_PER_LONG != 64
 /* This matches struct stat64 in glibc2.1. Only used for 32 bit. */
+#if __BITS_PER_LONG != 64 || defined(__ARCH_WANT_STAT64)
 struct stat64 {
        unsigned long long st_dev;      /* Device.  */
        unsigned long long st_ino;      /* File serial number.  */
index 1eb29399a4ff4b82f00257e3c03090015c00060a..334d68a171081472a25f98baa510bc7eb4cfeb8e 100644 (file)
@@ -1056,7 +1056,6 @@ struct lock_manager_operations {
        int (*fl_compare_owner)(struct file_lock *, struct file_lock *);
        void (*fl_notify)(struct file_lock *);  /* unblock callback */
        int (*fl_grant)(struct file_lock *, struct file_lock *, int);
-       void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
        void (*fl_release_private)(struct file_lock *);
        void (*fl_break)(struct file_lock *);
        int (*fl_mylease)(struct file_lock *, struct file_lock *);
index 8a389b608ce3b568e85d14dcbfb71f8f98cf0c13..41cb31f14ee3068cd3c232fb07e385676f2f9ba0 100644 (file)
  */
 #define in_nmi()       (preempt_count() & NMI_MASK)
 
-#if defined(CONFIG_PREEMPT)
+#if defined(CONFIG_PREEMPT) && defined(CONFIG_BKL)
 # define PREEMPT_INATOMIC_BASE kernel_locked()
-# define PREEMPT_CHECK_OFFSET 1
 #else
 # define PREEMPT_INATOMIC_BASE 0
+#endif
+
+#if defined(CONFIG_PREEMPT)
+# define PREEMPT_CHECK_OFFSET 1
+#else
 # define PREEMPT_CHECK_OFFSET 0
 #endif
 
index 1f66fa06a97cae66e39d3ad6f6cef8fc221ea955..889b35abaedac162061d01872237de109d62dbbb 100644 (file)
@@ -407,8 +407,6 @@ void i2c_unlock_adapter(struct i2c_adapter *);
 
 /* i2c adapter classes (bitmask) */
 #define I2C_CLASS_HWMON                (1<<0)  /* lm_sensors, ... */
-#define I2C_CLASS_TV_ANALOG    (1<<1)  /* bttv + friends */
-#define I2C_CLASS_TV_DIGITAL   (1<<2)  /* dvb cards */
 #define I2C_CLASS_DDC          (1<<3)  /* DDC bus on graphics adapters */
 #define I2C_CLASS_SPD          (1<<7)  /* SPD EEPROMs and similar */
 
index e9639115dff1b920095b79b92202767cd0ed0537..abde2527c699684f78cf029b82c740af751c26a2 100644 (file)
@@ -412,6 +412,11 @@ static inline void irq_free_desc(unsigned int irq)
        irq_free_descs(irq, 1);
 }
 
+static inline int irq_reserve_irq(unsigned int irq)
+{
+       return irq_reserve_irqs(irq, 1);
+}
+
 #endif /* CONFIG_GENERIC_HARDIRQS */
 
 #endif /* !CONFIG_S390 */
index 05aa8c23483ff502bdf94e76365236fa44ff9721..3bc4dcab6e828a16b6113c1aa1f3de08bb062c46 100644 (file)
@@ -43,7 +43,7 @@ unsigned int irq_get_next_irq(unsigned int offset);
                else
 
 #ifdef CONFIG_SMP
-#define irq_node(irq)  (irq_to_desc(irq)->node)
+#define irq_node(irq)  (irq_get_irq_data(irq)->node)
 #else
 #define irq_node(irq)  0
 #endif
index 87e2c2e7aed3757748ca69c8b22a96c5ee1d5752..c6bcfe93b9cab9deeab76844ce8b76e2a2adf5bb 100644 (file)
 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS  0x1c22
 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN        0x1c41
 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX        0x1c5f
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS     0x1d22
 #define PCI_DEVICE_ID_INTEL_PATSBURG_LPC       0x1d40
 #define PCI_DEVICE_ID_INTEL_82801AA_0  0x2410
 #define PCI_DEVICE_ID_INTEL_82801AA_1  0x2411
index 5310d27abd2a503ad523059ea4832f34ecfbb194..39fa04966aa892f220dded471b54e4b8930cd3e2 100644 (file)
@@ -29,9 +29,6 @@ struct semaphore {
 #define DEFINE_SEMAPHORE(name) \
        struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
 
-#define DECLARE_MUTEX(name)    \
-       struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
-
 static inline void sema_init(struct semaphore *sem, int val)
 {
        static struct lock_class_key __key;
@@ -39,9 +36,6 @@ static inline void sema_init(struct semaphore *sem, int val)
        lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0);
 }
 
-#define init_MUTEX(sem)                sema_init(sem, 1)
-#define init_MUTEX_LOCKED(sem) sema_init(sem, 0)
-
 extern void down(struct semaphore *sem);
 extern int __must_check down_interruptible(struct semaphore *sem);
 extern int __must_check down_killable(struct semaphore *sem);
index 4dca992f3093771993ac9d98d1233df5e2f33cfa..cea0c38e7a63dfad2544043c49fca25aea9a7563 100644 (file)
@@ -122,6 +122,10 @@ int clk_rate_table_find(struct clk *clk,
 long clk_rate_div_range_round(struct clk *clk, unsigned int div_min,
                              unsigned int div_max, unsigned long rate);
 
+long clk_round_parent(struct clk *clk, unsigned long target,
+                     unsigned long *best_freq, unsigned long *parent_freq,
+                     unsigned int div_min, unsigned int div_max);
+
 #define SH_CLK_MSTP32(_parent, _enable_reg, _enable_bit, _flags)       \
 {                                                                      \
        .parent         = _parent,                                      \
index 92e52a1e6af3fd8478bb451f04d34a3c63b1625f..b4d7710bc38d2b26effd6025243150490e0a26a9 100644 (file)
@@ -204,6 +204,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
 /**
  * struct spi_master - interface to SPI master controller
  * @dev: device interface to this driver
+ * @list: link with the global spi_master list
  * @bus_num: board-specific (and often SOC-specific) identifier for a
  *     given SPI controller.
  * @num_chipselect: chipselects are used to distinguish individual
@@ -238,6 +239,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
 struct spi_master {
        struct device   dev;
 
+       struct list_head list;
+
        /* other than negative (== assign one dynamically), bus_num is fully
         * board-specific.  usually that simplifies to being SOC-specific.
         * example:  one SOC has three SPI controllers, numbered 0..2,
index 6da573c75d54cfdde09f449f6cd3dd617c49fa20..8eff83b95366049b6f55d9efd268952453329227 100644 (file)
@@ -28,7 +28,7 @@ struct caif_param {
  * @sockaddr:          Socket address to connect.
  * @priority:          Priority of the connection.
  * @link_selector:     Link selector (high bandwidth or low latency)
- * @link_name:         Name of the CAIF Link Layer to use.
+ * @ifindex:           kernel index of the interface.
  * @param:             Connect Request parameters (CAIF_SO_REQ_PARAM).
  *
  * This struct is used when connecting a CAIF channel.
@@ -39,7 +39,7 @@ struct caif_connect_request {
        struct sockaddr_caif sockaddr;
        enum caif_channel_priority priority;
        enum caif_link_selector link_selector;
-       char link_name[16];
+       int ifindex;
        struct caif_param param;
 };
 
index ce4570dff020720c2ca6d5e22a0202a78c5c42c5..87c3d11b8e555ff2ebd9a07f504cd8ab2b5fcebd 100644 (file)
@@ -121,6 +121,8 @@ struct cfspi {
        wait_queue_head_t wait;
        spinlock_t lock;
        bool flow_stop;
+       bool slave;
+       bool slave_talked;
 #ifdef CONFIG_DEBUG_FS
        enum cfspi_state dbg_state;
        u16 pcmd;
index bd646faffa47bd8cd46ed4f15e1988c7bfac8247..f688478bfb84a4afc62039e57e212978ab24929b 100644 (file)
@@ -139,10 +139,10 @@ struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
                     enum cfcnfg_phy_preference phy_pref);
 
 /**
- * cfcnfg_get_named() - Get the Physical Identifier of CAIF Link Layer
+ * cfcnfg_get_id_from_ifi() - Get the Physical Identifier of ifindex,
+ *                     it matches caif physical id with the kernel interface id.
  * @cnfg:      Configuration object
- * @name:      Name of the Physical Layer (Caif Link Layer)
+ * @ifi:       ifindex obtained from socket.c bindtodevice.
  */
-int cfcnfg_get_named(struct cfcnfg *cnfg, char *name);
-
+int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi);
 #endif                         /* CFCNFG_H_ */
index f3b201d335b3532858c846a8aadb1672de80dce3..9801c55de5d64e5357006f9cfb129bce139572dd 100644 (file)
@@ -384,7 +384,7 @@ static inline int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen,
  *
  * Returns the first attribute which matches the specified type.
  */
-static inline struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh,
+static inline struct nlattr *nlmsg_find_attr(const struct nlmsghdr *nlh,
                                             int hdrlen, int attrtype)
 {
        return nla_find(nlmsg_attrdata(nlh, hdrlen),
index 14be49b44e841ff22aa66e5b291a6ed5b00978c3..f986ab7ffe6f040e9e00ac23d404bd8ad31e1f4e 100644 (file)
@@ -721,7 +721,7 @@ struct libfc_function_template {
  * struct fc_disc - Discovery context
  * @retry_count:   Number of retries
  * @pending:       1 if discovery is pending, 0 if not
- * @requesting:    1 if discovery has been requested, 0 if not
+ * @requested:     1 if discovery has been requested, 0 if not
  * @seq_count:     Number of sequences used for discovery
  * @buf_len:       Length of the discovery buffer
  * @disc_id:       Discovery ID
index a8f37012663209020b30baeecabde62512465993..53a9e886612b8c30fd4b4fc3d2814a9433bb551b 100644 (file)
@@ -137,7 +137,7 @@ struct osd_request {
                void *buff;
                unsigned alloc_size; /* 0 here means: don't call kfree */
                unsigned total_bytes;
-       } set_attr, enc_get_attr, get_attr;
+       } cdb_cont, set_attr, enc_get_attr, get_attr;
 
        struct _osd_io_info {
                struct bio *bio;
@@ -448,6 +448,20 @@ void osd_req_read(struct osd_request *or,
 int osd_req_read_kern(struct osd_request *or,
        const struct osd_obj_id *obj, u64 offset, void *buff, u64 len);
 
+/* Scatter/Gather write/read commands */
+int osd_req_write_sg(struct osd_request *or,
+       const struct osd_obj_id *obj, struct bio *bio,
+       const struct osd_sg_entry *sglist, unsigned numentries);
+int osd_req_read_sg(struct osd_request *or,
+       const struct osd_obj_id *obj, struct bio *bio,
+       const struct osd_sg_entry *sglist, unsigned numentries);
+int osd_req_write_sg_kern(struct osd_request *or,
+       const struct osd_obj_id *obj, void **buff,
+       const struct osd_sg_entry *sglist, unsigned numentries);
+int osd_req_read_sg_kern(struct osd_request *or,
+       const struct osd_obj_id *obj, void **buff,
+       const struct osd_sg_entry *sglist, unsigned numentries);
+
 /*
  * Root/Partition/Collection/Object Attributes commands
  */
index 685661283540f64beb081b291dc6689c0a255fc0..a6026da25f3e0bf5787d479e1511da85c1175299 100644 (file)
@@ -631,4 +631,46 @@ static inline void osd_sec_set_caps(struct osd_capability_head *cap,
        put_unaligned_le16(bit_mask, &cap->permissions_bit_mask);
 }
 
+/* osd2r05a sec 5.3: CDB continuation segment formats */
+enum osd_continuation_segment_format {
+       CDB_CONTINUATION_FORMAT_V2 = 0x01,
+};
+
+struct osd_continuation_segment_header {
+       u8      format;
+       u8      reserved1;
+       __be16  service_action;
+       __be32  reserved2;
+       u8      integrity_check[OSDv2_CRYPTO_KEYID_SIZE];
+} __packed;
+
+/* osd2r05a sec 5.4.1: CDB continuation descriptors */
+enum osd_continuation_descriptor_type {
+       NO_MORE_DESCRIPTORS = 0x0000,
+       SCATTER_GATHER_LIST = 0x0001,
+       QUERY_LIST = 0x0002,
+       USER_OBJECT = 0x0003,
+       COPY_USER_OBJECT_SOURCE = 0x0101,
+       EXTENSION_CAPABILITIES = 0xFFEE
+};
+
+struct osd_continuation_descriptor_header {
+       __be16  type;
+       u8      reserved;
+       u8      pad_length;
+       __be32  length;
+} __packed;
+
+
+/* osd2r05a sec 5.4.2: Scatter/gather list */
+struct osd_sg_list_entry {
+       __be64 offset;
+       __be64 len;
+};
+
+struct osd_sg_continuation_descriptor {
+       struct osd_continuation_descriptor_header hdr;
+       struct osd_sg_list_entry entries[];
+};
+
 #endif /* ndef __OSD_PROTOCOL_H__ */
index 3f5e88cc75c0b8a1d54b25902e82017f5bfd51f5..bd0be7ed4bcf619ca4aea8cfa3abc6d86d9c7aec 100644 (file)
@@ -37,4 +37,9 @@ struct osd_attr {
        void *val_ptr;          /* in network order */
 };
 
+struct osd_sg_entry {
+       u64 offset;
+       u64 len;
+};
+
 #endif /* ndef __OSD_TYPES_H__ */
index 289010d3270bfa99191cfbdfa95a02564b6638bf..e5e345fb2a5c37db45de06bcdf02f3796aec64c4 100644 (file)
@@ -98,6 +98,103 @@ TRACE_EVENT(ext4_allocate_inode,
                  (unsigned long) __entry->dir, __entry->mode)
 );
 
+TRACE_EVENT(ext4_evict_inode,
+       TP_PROTO(struct inode *inode),
+
+       TP_ARGS(inode),
+
+       TP_STRUCT__entry(
+               __field(        int,   dev_major                )
+               __field(        int,   dev_minor                )
+               __field(        ino_t,  ino                     )
+               __field(        int,    nlink                   )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->ino    = inode->i_ino;
+               __entry->nlink  = inode->i_nlink;
+       ),
+
+       TP_printk("dev %d,%d ino %lu nlink %d",
+                 __entry->dev_major, __entry->dev_minor,
+                 (unsigned long) __entry->ino, __entry->nlink)
+);
+
+TRACE_EVENT(ext4_drop_inode,
+       TP_PROTO(struct inode *inode, int drop),
+
+       TP_ARGS(inode, drop),
+
+       TP_STRUCT__entry(
+               __field(        int,    dev_major               )
+               __field(        int,    dev_minor               )
+               __field(        ino_t,  ino                     )
+               __field(        int,    drop                    )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->ino    = inode->i_ino;
+               __entry->drop   = drop;
+       ),
+
+       TP_printk("dev %d,%d ino %lu drop %d",
+                 __entry->dev_major, __entry->dev_minor,
+                 (unsigned long) __entry->ino, __entry->drop)
+);
+
+TRACE_EVENT(ext4_mark_inode_dirty,
+       TP_PROTO(struct inode *inode, unsigned long IP),
+
+       TP_ARGS(inode, IP),
+
+       TP_STRUCT__entry(
+               __field(        int,    dev_major               )
+               __field(        int,    dev_minor               )
+               __field(        ino_t,  ino                     )
+               __field(unsigned long,  ip                      )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->ino    = inode->i_ino;
+               __entry->ip     = IP;
+       ),
+
+       TP_printk("dev %d,%d ino %lu caller %pF",
+                 __entry->dev_major, __entry->dev_minor,
+                 (unsigned long) __entry->ino, (void *)__entry->ip)
+);
+
+TRACE_EVENT(ext4_begin_ordered_truncate,
+       TP_PROTO(struct inode *inode, loff_t new_size),
+
+       TP_ARGS(inode, new_size),
+
+       TP_STRUCT__entry(
+               __field(        int,    dev_major               )
+               __field(        int,    dev_minor               )
+               __field(        ino_t,  ino                     )
+               __field(        loff_t, new_size                )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major      = MAJOR(inode->i_sb->s_dev);
+               __entry->dev_minor      = MINOR(inode->i_sb->s_dev);
+               __entry->ino            = inode->i_ino;
+               __entry->new_size       = new_size;
+       ),
+
+       TP_printk("dev %d,%d ino %lu new_size %lld",
+                 __entry->dev_major, __entry->dev_minor,
+                 (unsigned long) __entry->ino,
+                 (long long) __entry->new_size)
+);
+
 DECLARE_EVENT_CLASS(ext4__write_begin,
 
        TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
index b194febf5799bab766e5aef261e566902a086b28..21aa7b3001fb49edce43446dd85898f62ab33d98 100644 (file)
@@ -95,6 +95,14 @@ static void __exit_signal(struct task_struct *tsk)
                tty = sig->tty;
                sig->tty = NULL;
        } else {
+               /*
+                * This can only happen if the caller is de_thread().
+                * FIXME: this is the temporary hack, we should teach
+                * posix-cpu-timers to handle this case correctly.
+                */
+               if (unlikely(has_group_leader_pid(tsk)))
+                       posix_cpu_timers_exit_group(tsk);
+
                /*
                 * If there is any task waiting for the group exit
                 * then notify it:
index 644e8d5fa367e74c3cc06a2114f2e283c701b0e6..5f92acc5f952e0afb0489017c265a943a4a7d464 100644 (file)
@@ -324,6 +324,10 @@ void enable_irq(unsigned int irq)
        if (!desc)
                return;
 
+       if (WARN(!desc->irq_data.chip || !desc->irq_data.chip->irq_enable,
+           KERN_ERR "enable_irq before setup/request_irq: irq %u\n", irq))
+               return;
+
        chip_bus_lock(desc);
        raw_spin_lock_irqsave(&desc->lock, flags);
        __enable_irq(desc, irq, false);
index c7cf397fb92958bbcbd2772e13a8d4a4d9c00b6d..859ea5a9605fa40fe47aedcb865ab08c66a43797 100644 (file)
@@ -70,17 +70,10 @@ static const struct vm_operations_struct relay_file_mmap_ops = {
  */
 static struct page **relay_alloc_page_array(unsigned int n_pages)
 {
-       struct page **array;
-       size_t pa_size = n_pages * sizeof(struct page *);
-
-       if (pa_size > PAGE_SIZE) {
-               array = vmalloc(pa_size);
-               if (array)
-                       memset(array, 0, pa_size);
-       } else {
-               array = kzalloc(pa_size, GFP_KERNEL);
-       }
-       return array;
+       const size_t pa_size = n_pages * sizeof(struct page *);
+       if (pa_size > PAGE_SIZE)
+               return vzalloc(pa_size);
+       return kzalloc(pa_size, GFP_KERNEL);
 }
 
 /*
index bafba687a6d849a11f0201acd3d7ae5e63e9301e..6e3c41a4024c1cc66be01218e2c37498498f2469 100644 (file)
@@ -43,7 +43,7 @@ static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
 static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
 #endif
 
-static int __initdata no_watchdog;
+static int no_watchdog;
 
 
 /* boot commands */
index 75572b5f23746a4b47a42920980a22e6a5251fe7..61ba5e405791918e2bab077144300b1d4d7ab6ce 100644 (file)
@@ -1563,8 +1563,10 @@ retry_find:
                        goto no_cached_page;
        }
 
-       if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags))
+       if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags)) {
+               page_cache_release(page);
                return ret | VM_FAULT_RETRY;
+       }
 
        /* Did it get truncated? */
        if (unlikely(page->mapping != mapping)) {
index cd2e42be7b68f73dc60f40631f2b9f87708d3b47..42eac4d33216b81c307a87016e821051bc86146e 100644 (file)
@@ -949,7 +949,7 @@ static void *vmstat_start(struct seq_file *m, loff_t *pos)
        v[PGPGIN] /= 2;         /* sectors -> kbytes */
        v[PGPGOUT] /= 2;
 #endif
-       return m->private + *pos;
+       return (unsigned long *)m->private + *pos;
 }
 
 static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
index 76ae68303d3a3675265e61eccc213a0c4526d4e1..d522d8c1703e761eb27b4e2375eff9851b06690e 100644 (file)
@@ -16,11 +16,18 @@ int connect_req_to_link_param(struct cfcnfg *cnfg,
 {
        struct dev_info *dev_info;
        enum cfcnfg_phy_preference pref;
+       int res;
+
        memset(l, 0, sizeof(*l));
-       l->priority = s->priority;
+       /* In caif protocol low value is high priority */
+       l->priority = CAIF_PRIO_MAX - s->priority + 1;
 
-       if (s->link_name[0] != '\0')
-               l->phyid = cfcnfg_get_named(cnfg, s->link_name);
+       if (s->ifindex != 0){
+               res = cfcnfg_get_id_from_ifi(cnfg, s->ifindex);
+               if (res < 0)
+                       return res;
+               l->phyid = res;
+       }
        else {
                switch (s->link_selector) {
                case CAIF_LINK_HIGH_BANDW:
index b99369a055d13df6414421a28cfaee5d000c6c72..a42a408306e4a1c038aa6ad0d8fb3d0e2f923aa9 100644 (file)
@@ -307,6 +307,8 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
 
        case NETDEV_UNREGISTER:
                caifd = caif_get(dev);
+               if (caifd == NULL)
+                       break;
                netdev_info(dev, "unregister\n");
                atomic_set(&caifd->state, what);
                caif_device_destroy(dev);
index 2eca2dd0000fd7dce7fc614ed5e476f0ca886874..1bf0cf503796f27668d8dc8c1e9a733fd6e76bdd 100644 (file)
@@ -716,8 +716,7 @@ static int setsockopt(struct socket *sock,
 {
        struct sock *sk = sock->sk;
        struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
-       int prio, linksel;
-       struct ifreq ifreq;
+       int linksel;
 
        if (cf_sk->sk.sk_socket->state != SS_UNCONNECTED)
                return -ENOPROTOOPT;
@@ -735,33 +734,6 @@ static int setsockopt(struct socket *sock,
                release_sock(&cf_sk->sk);
                return 0;
 
-       case SO_PRIORITY:
-               if (lvl != SOL_SOCKET)
-                       goto bad_sol;
-               if (ol < sizeof(int))
-                       return -EINVAL;
-               if (copy_from_user(&prio, ov, sizeof(int)))
-                       return -EINVAL;
-               lock_sock(&(cf_sk->sk));
-               cf_sk->conn_req.priority = prio;
-               release_sock(&cf_sk->sk);
-               return 0;
-
-       case SO_BINDTODEVICE:
-               if (lvl != SOL_SOCKET)
-                       goto bad_sol;
-               if (ol < sizeof(struct ifreq))
-                       return -EINVAL;
-               if (copy_from_user(&ifreq, ov, sizeof(ifreq)))
-                       return -EFAULT;
-               lock_sock(&(cf_sk->sk));
-               strncpy(cf_sk->conn_req.link_name, ifreq.ifr_name,
-                       sizeof(cf_sk->conn_req.link_name));
-               cf_sk->conn_req.link_name
-                       [sizeof(cf_sk->conn_req.link_name)-1] = 0;
-               release_sock(&cf_sk->sk);
-               return 0;
-
        case CAIFSO_REQ_PARAM:
                if (lvl != SOL_CAIF)
                        goto bad_sol;
@@ -880,6 +852,18 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
        sock->state = SS_CONNECTING;
        sk->sk_state = CAIF_CONNECTING;
 
+       /* Check priority value comming from socket */
+       /* if priority value is out of range it will be ajusted */
+       if (cf_sk->sk.sk_priority > CAIF_PRIO_MAX)
+               cf_sk->conn_req.priority = CAIF_PRIO_MAX;
+       else if (cf_sk->sk.sk_priority < CAIF_PRIO_MIN)
+               cf_sk->conn_req.priority = CAIF_PRIO_MIN;
+       else
+               cf_sk->conn_req.priority = cf_sk->sk.sk_priority;
+
+       /*ifindex = id of the interface.*/
+       cf_sk->conn_req.ifindex = cf_sk->sk.sk_bound_dev_if;
+
        dbfs_atomic_inc(&cnt.num_connect_req);
        cf_sk->layer.receive = caif_sktrecv_cb;
        err = caif_connect_client(&cf_sk->conn_req,
@@ -905,6 +889,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
        cf_sk->maxframe = mtu - (headroom + tailroom);
        if (cf_sk->maxframe < 1) {
                pr_warn("CAIF Interface MTU too small (%d)\n", dev->mtu);
+               err = -ENODEV;
                goto out;
        }
 
@@ -1142,7 +1127,7 @@ static int caif_create(struct net *net, struct socket *sock, int protocol,
        set_rx_flow_on(cf_sk);
 
        /* Set default options on configuration */
-       cf_sk->conn_req.priority = CAIF_PRIO_NORMAL;
+       cf_sk->sk.sk_priority= CAIF_PRIO_NORMAL;
        cf_sk->conn_req.link_selector = CAIF_LINK_LOW_LATENCY;
        cf_sk->conn_req.protocol = protocol;
        /* Increase the number of sockets created. */
index 41adafd1891422ab1aa32a95a46aee7d9ae77b82..21ede141018abf698a58bcf946e0058d6d06c499 100644 (file)
@@ -173,18 +173,15 @@ static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo(struct cfcnfg *cnfg,
        return NULL;
 }
 
-int cfcnfg_get_named(struct cfcnfg *cnfg, char *name)
+
+int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi)
 {
        int i;
-
-       /* Try to match with specified name */
-       for (i = 0; i < MAX_PHY_LAYERS; i++) {
-               if (cnfg->phy_layers[i].frm_layer != NULL
-                   && strcmp(cnfg->phy_layers[i].phy_layer->name,
-                             name) == 0)
-                       return cnfg->phy_layers[i].frm_layer->id;
-       }
-       return 0;
+       for (i = 0; i < MAX_PHY_LAYERS; i++)
+               if (cnfg->phy_layers[i].frm_layer != NULL &&
+                               cnfg->phy_layers[i].ifindex == ifi)
+                       return i;
+       return -ENODEV;
 }
 
 int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
index 08f267a109aa3c677efc4a6795ccfea31fc8d581..3cd8f978e3098288d9d1e114347e1ba2c0e4936c 100644 (file)
@@ -361,11 +361,10 @@ void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer)
        struct cfctrl_request_info *p, *tmp;
        struct cfctrl *ctrl = container_obj(layr);
        spin_lock(&ctrl->info_list_lock);
-       pr_warn("enter\n");
 
        list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
                if (p->client_layer == adap_layer) {
-                       pr_warn("cancel req :%d\n", p->sequence_no);
+                       pr_debug("cancel req :%d\n", p->sequence_no);
                        list_del(&p->list);
                        kfree(p);
                }
index 496fda9ac66f56bee42568e8c0386566c3208be4..11a2af4c162ab6a8324ebaf6b8063ced01b1aea6 100644 (file)
@@ -12,6 +12,8 @@
 #include <net/caif/cfsrvl.h>
 #include <net/caif/cfpkt.h>
 
+#define container_obj(layr) ((struct cfsrvl *) layr)
+
 static int cfdbgl_receive(struct cflayer *layr, struct cfpkt *pkt);
 static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt);
 
@@ -38,5 +40,17 @@ static int cfdbgl_receive(struct cflayer *layr, struct cfpkt *pkt)
 
 static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt)
 {
+       struct cfsrvl *service = container_obj(layr);
+       struct caif_payload_info *info;
+       int ret;
+
+       if (!cfsrvl_ready(service, &ret))
+               return ret;
+
+       /* Add info for MUX-layer to route the packet out */
+       info = cfpkt_info(pkt);
+       info->channel_id = service->layer.id;
+       info->dev_info = &service->dev_info;
+
        return layr->dn->transmit(layr->dn, pkt);
 }
index bde8481e8d2574dd939f84595f8e4354370aa5a7..e2fb5fa757951a46e8d6be9326ffc1659f943232 100644 (file)
@@ -193,7 +193,7 @@ out:
 
 static int cfrfml_transmit_segment(struct cfrfml *rfml, struct cfpkt *pkt)
 {
-       caif_assert(cfpkt_getlen(pkt) >= rfml->fragment_size);
+       caif_assert(cfpkt_getlen(pkt) < rfml->fragment_size);
 
        /* Add info for MUX-layer to route the packet out. */
        cfpkt_info(pkt)->channel_id = rfml->serv.layer.id;
index 35dfb83184833302e616dca6b0985faeb533897d..0dd54a69dace255fcdf54732d982e8c521c574a5 100644 (file)
@@ -2131,7 +2131,7 @@ static struct netdev_queue *dev_pick_tx(struct net_device *dev,
        } else {
                struct sock *sk = skb->sk;
                queue_index = sk_tx_queue_get(sk);
-               if (queue_index < 0) {
+               if (queue_index < 0 || queue_index >= dev->real_num_tx_queues) {
 
                        queue_index = 0;
                        if (dev->real_num_tx_queues > 1)
index a29edf2219c8437b811bcce27fdd2cd9fca0a9fc..c079cc0ec6515fe212aecd27303c2b5671a5d60d 100644 (file)
@@ -47,11 +47,8 @@ extern int fib_detect_death(struct fib_info *fi, int order,
 static inline void fib_result_assign(struct fib_result *res,
                                     struct fib_info *fi)
 {
-       if (res->fi != NULL)
-               fib_info_put(res->fi);
+       /* we used to play games with refcounts, but we now use RCU */
        res->fi = fi;
-       if (fi != NULL)
-               atomic_inc(&fi->fib_clntref);
 }
 
 #endif /* _FIB_LOOKUP_H */
index ba80426658498ba4082c54a19c5af2d2c00cdb10..2ada17129fce6ac9a7285f6033e30d0a9bc4b98a 100644 (file)
@@ -490,9 +490,11 @@ static int inet_csk_diag_dump(struct sock *sk,
 {
        struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
 
-       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
+       if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
                struct inet_diag_entry entry;
-               struct rtattr *bc = (struct rtattr *)(r + 1);
+               const struct nlattr *bc = nlmsg_find_attr(cb->nlh,
+                                                         sizeof(*r),
+                                                         INET_DIAG_REQ_BYTECODE);
                struct inet_sock *inet = inet_sk(sk);
 
                entry.family = sk->sk_family;
@@ -512,7 +514,7 @@ static int inet_csk_diag_dump(struct sock *sk,
                entry.dport = ntohs(inet->inet_dport);
                entry.userlocks = sk->sk_userlocks;
 
-               if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
+               if (!inet_diag_bc_run(nla_data(bc), nla_len(bc), &entry))
                        return 0;
        }
 
@@ -527,9 +529,11 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
 {
        struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
 
-       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
+       if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
                struct inet_diag_entry entry;
-               struct rtattr *bc = (struct rtattr *)(r + 1);
+               const struct nlattr *bc = nlmsg_find_attr(cb->nlh,
+                                                         sizeof(*r),
+                                                         INET_DIAG_REQ_BYTECODE);
 
                entry.family = tw->tw_family;
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
@@ -548,7 +552,7 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
                entry.dport = ntohs(tw->tw_dport);
                entry.userlocks = 0;
 
-               if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
+               if (!inet_diag_bc_run(nla_data(bc), nla_len(bc), &entry))
                        return 0;
        }
 
@@ -618,7 +622,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
        struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct listen_sock *lopt;
-       struct rtattr *bc = NULL;
+       const struct nlattr *bc = NULL;
        struct inet_sock *inet = inet_sk(sk);
        int j, s_j;
        int reqnum, s_reqnum;
@@ -638,8 +642,9 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
        if (!lopt || !lopt->qlen)
                goto out;
 
-       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
-               bc = (struct rtattr *)(r + 1);
+       if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
+               bc = nlmsg_find_attr(cb->nlh, sizeof(*r),
+                                    INET_DIAG_REQ_BYTECODE);
                entry.sport = inet->inet_num;
                entry.userlocks = sk->sk_userlocks;
        }
@@ -672,8 +677,8 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
                                        &ireq->rmt_addr;
                                entry.dport = ntohs(ireq->rmt_port);
 
-                               if (!inet_diag_bc_run(RTA_DATA(bc),
-                                                   RTA_PAYLOAD(bc), &entry))
+                               if (!inet_diag_bc_run(nla_data(bc),
+                                                     nla_len(bc), &entry))
                                        continue;
                        }
 
index 3cad2591ace0c15fdad446ab528b0f40c2624d09..3fac340a28d5394bd95bd649d5bcee3dcb3d24df 100644 (file)
@@ -927,6 +927,7 @@ static int get_info(struct net *net, void __user *user,
                        private = &tmp;
                }
 #endif
+               memset(&info, 0, sizeof(info));
                info.valid_hooks = t->valid_hooks;
                memcpy(info.hook_entry, private->hook_entry,
                       sizeof(info.hook_entry));
index d31b007a6d80dcda45f7f7913ec72af7556b79bf..a846d633b3b6f04a3ed72be1d884e484d3efa030 100644 (file)
@@ -1124,6 +1124,7 @@ static int get_info(struct net *net, void __user *user,
                        private = &tmp;
                }
 #endif
+               memset(&info, 0, sizeof(info));
                info.valid_hooks = t->valid_hooks;
                memcpy(info.hook_entry, private->hook_entry,
                       sizeof(info.hook_entry));
index 295c97431e4358408dc45fc7c493536bb41434fc..c04787ce1a71203e1346830450b0a130e358defc 100644 (file)
@@ -47,26 +47,6 @@ __nf_nat_proto_find(u_int8_t protonum)
        return rcu_dereference(nf_nat_protos[protonum]);
 }
 
-static const struct nf_nat_protocol *
-nf_nat_proto_find_get(u_int8_t protonum)
-{
-       const struct nf_nat_protocol *p;
-
-       rcu_read_lock();
-       p = __nf_nat_proto_find(protonum);
-       if (!try_module_get(p->me))
-               p = &nf_nat_unknown_protocol;
-       rcu_read_unlock();
-
-       return p;
-}
-
-static void
-nf_nat_proto_put(const struct nf_nat_protocol *p)
-{
-       module_put(p->me);
-}
-
 /* We keep an extra hash for each conntrack, for fast searching. */
 static inline unsigned int
 hash_by_src(const struct net *net, u16 zone,
@@ -588,6 +568,26 @@ static struct nf_ct_ext_type nat_extend __read_mostly = {
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_conntrack.h>
 
+static const struct nf_nat_protocol *
+nf_nat_proto_find_get(u_int8_t protonum)
+{
+       const struct nf_nat_protocol *p;
+
+       rcu_read_lock();
+       p = __nf_nat_proto_find(protonum);
+       if (!try_module_get(p->me))
+               p = &nf_nat_unknown_protocol;
+       rcu_read_unlock();
+
+       return p;
+}
+
+static void
+nf_nat_proto_put(const struct nf_nat_protocol *p)
+{
+       module_put(p->me);
+}
+
 static const struct nla_policy protonat_nla_policy[CTA_PROTONAT_MAX+1] = {
        [CTA_PROTONAT_PORT_MIN] = { .type = NLA_U16 },
        [CTA_PROTONAT_PORT_MAX] = { .type = NLA_U16 },
index 51df035897e77dfa5b89e6328817cfcb638702cb..455582384eced0b9242a40ea523ac31c8d6e08f4 100644 (file)
@@ -1137,6 +1137,7 @@ static int get_info(struct net *net, void __user *user,
                        private = &tmp;
                }
 #endif
+               memset(&info, 0, sizeof(info));
                info.valid_hooks = t->valid_hooks;
                memcpy(info.hook_entry, private->hook_entry,
                       sizeof(info.hook_entry));
index 25661f968f3fb2c2976575f4233fd03c42edb863..fc328339be99f5c0c1fe5ffcb484e72b51b63e90 100644 (file)
@@ -2741,6 +2741,7 @@ static void __net_exit ip6_route_net_exit(struct net *net)
        kfree(net->ipv6.ip6_prohibit_entry);
        kfree(net->ipv6.ip6_blk_hole_entry);
 #endif
+       dst_entries_destroy(&net->ipv6.ip6_dst_ops);
 }
 
 static struct pernet_operations ip6_route_net_ops = {
@@ -2832,5 +2833,6 @@ void ip6_route_cleanup(void)
        xfrm6_fini();
        fib6_gc_cleanup();
        unregister_pernet_subsys(&ip6_route_net_ops);
+       dst_entries_destroy(&ip6_dst_blackhole_ops);
        kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
 }
index 104ec3b283d4159f610ef61548beb512d053dcd3..b8dbae82fab8612974d603c42b4cbac3b0509165 100644 (file)
@@ -249,7 +249,7 @@ static int l2tp_dfs_seq_open(struct inode *inode, struct file *file)
        struct seq_file *seq;
        int rc = -ENOMEM;
 
-       pd = kzalloc(GFP_KERNEL, sizeof(*pd));
+       pd = kzalloc(sizeof(*pd), GFP_KERNEL);
        if (pd == NULL)
                goto out;
 
index 1eacf8d9966aa292f7f051964f822a00c0ab6605..27a5ea6b6a0ff1a644205ca705f717c78b4dcc84 100644 (file)
@@ -1312,7 +1312,8 @@ void *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced, int nulls)
        if (!hash) {
                *vmalloced = 1;
                printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n");
-               hash = __vmalloc(sz, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+               hash = __vmalloc(sz, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
+                                PAGE_KERNEL);
        }
 
        if (hash && nulls)
index ed6d929580236c1b4aa77a42db959c9e522f2fc5..dc7bb74110df22818b42222450f0141068b79b6d 100644 (file)
@@ -292,6 +292,12 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
 
                for (i = 0; i < MAX_NF_CT_PROTO; i++)
                        proto_array[i] = &nf_conntrack_l4proto_generic;
+
+               /* Before making proto_array visible to lockless readers,
+                * we must make sure its content is committed to memory.
+                */
+               smp_wmb();
+
                nf_ct_protos[l4proto->l3proto] = proto_array;
        } else if (nf_ct_protos[l4proto->l3proto][l4proto->l4proto] !=
                                        &nf_conntrack_l4proto_generic) {
index c390156b426fc936c6b05fd607f4c32ddb1e3a81..aeec1d483b17e6f65c858e1510c7752965e35260 100644 (file)
@@ -134,8 +134,12 @@ static int rds_loop_conn_alloc(struct rds_connection *conn, gfp_t gfp)
 static void rds_loop_conn_free(void *arg)
 {
        struct rds_loop_connection *lc = arg;
+       unsigned long flags;
+
        rdsdebug("lc %p\n", lc);
+       spin_lock_irqsave(&loop_conns_lock, flags);
        list_del(&lc->loop_node);
+       spin_unlock_irqrestore(&loop_conns_lock, flags);
        kfree(lc);
 }
 
index 08a8c6cf2d100f8f05a6c932d8190326277747e9..8e0a32001c90c531a2ad8361dc4bb0c399b812fe 100644 (file)
@@ -221,7 +221,13 @@ static int rds_tcp_conn_alloc(struct rds_connection *conn, gfp_t gfp)
 static void rds_tcp_conn_free(void *arg)
 {
        struct rds_tcp_connection *tc = arg;
+       unsigned long flags;
        rdsdebug("freeing tc %p\n", tc);
+
+       spin_lock_irqsave(&rds_tcp_conn_lock, flags);
+       list_del(&tc->t_tcp_node);
+       spin_unlock_irqrestore(&rds_tcp_conn_lock, flags);
+
        kmem_cache_free(rds_tcp_conn_slab, tc);
 }
 
index 37dff78e9cb17c6fcf35e5302d57b84dd5e9f5f9..d49c40fb7e0960daa905353e714e9317dd38088b 100644 (file)
@@ -34,8 +34,6 @@ struct cgroup_subsys net_cls_subsys = {
        .populate       = cgrp_populate,
 #ifdef CONFIG_NET_CLS_CGROUP
        .subsys_id      = net_cls_subsys_id,
-#else
-#define net_cls_subsys_id net_cls_subsys.subsys_id
 #endif
        .module         = THIS_MODULE,
 };
index 763253257411af1db91b3e25a78af8e687523342..ea8f566e720c7bd9ed508647c080c5c554edba2b 100644 (file)
@@ -103,7 +103,8 @@ retry:
 
 static void em_text_destroy(struct tcf_proto *tp, struct tcf_ematch *m)
 {
-       textsearch_destroy(EM_TEXT_PRIV(m)->config);
+       if (EM_TEXT_PRIV(m) && EM_TEXT_PRIV(m)->config)
+               textsearch_destroy(EM_TEXT_PRIV(m)->config);
 }
 
 static int em_text_dump(struct sk_buff *skb, struct tcf_ematch *m)
index 771bab00754b0baff1a5c7a95892028857c8b84d..3a8c4c419cd4051ce0ce7a586b3d93417f768cb2 100644 (file)
@@ -134,15 +134,15 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                case X25_FAC_CLASS_D:
                        switch (*p) {
                        case X25_FAC_CALLING_AE:
-                               if (p[1] > X25_MAX_DTE_FACIL_LEN)
-                                       break;
+                               if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
+                                       return 0;
                                dte_facs->calling_len = p[2];
                                memcpy(dte_facs->calling_ae, &p[3], p[1] - 1);
                                *vc_fac_mask |= X25_MASK_CALLING_AE;
                                break;
                        case X25_FAC_CALLED_AE:
-                               if (p[1] > X25_MAX_DTE_FACIL_LEN)
-                                       break;
+                               if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
+                                       return 0;
                                dte_facs->called_len = p[2];
                                memcpy(dte_facs->called_ae, &p[3], p[1] - 1);
                                *vc_fac_mask |= X25_MASK_CALLED_AE;
index 63178961efac00488d36e7c8fc3d21f00e036e2e..f729f022be69bc8c32b1008e8943c92cf36c1e28 100644 (file)
@@ -119,6 +119,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                                                &x25->vc_facil_mask);
                        if (len > 0)
                                skb_pull(skb, len);
+                       else
+                               return -1;
                        /*
                         *      Copy any Call User Data.
                         */
index 90b54d4697fd2de9ae1dcecc80fc25cdcab63d21..e3c7fc0dca382492f1714f4879abb37b63cc07f2 100755 (executable)
@@ -2794,12 +2794,8 @@ sub process {
                        WARN("__func__ should be used instead of gcc specific __FUNCTION__\n"  . $herecurr);
                }
 
-# check for semaphores used as mutexes
-               if ($line =~ /^.\s*(DECLARE_MUTEX|init_MUTEX)\s*\(/) {
-                       WARN("mutexes are preferred for single holder semaphores\n" . $herecurr);
-               }
-# check for semaphores used as mutexes
-               if ($line =~ /^.\s*init_MUTEX_LOCKED\s*\(/) {
+# check for semaphores initialized locked
+               if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) {
                        WARN("consider using a completion\n" . $herecurr);
 
                }
index c0efe102d655c40547afe92014cec1c74b70b3c2..af6e9f3de9503b033a69a3eba7c2ecd212fef747 100644 (file)
@@ -875,7 +875,7 @@ const char *sym_expand_string_value(const char *in)
                        symval = sym_get_string_value(sym);
                }
 
-               newlen = strlen(res) + strlen(symval) + strlen(src);
+               newlen = strlen(res) + strlen(symval) + strlen(src) + 1;
                if (newlen > reslen) {
                        reslen = newlen;
                        res = realloc(res, reslen);
index f7e374ec44144763feb215890c73714b32a17a22..1b9bf9395cfe820f87b34fa14d57d5a667a67217 100644 (file)
@@ -625,6 +625,8 @@ static short create_adapter_obj(struct hpi_adapter_obj *pao,
                        control_cache_size, (struct hpi_control_cache_info *)
                        &phw->control_cache[0]
                        );
+               if (!phw->p_cache)
+                       pao->has_control_cache = 0;
        } else
                pao->has_control_cache = 0;
 
index 22c5fc6255335ac94aca5ac297432f16b0950c4e..2672f6591ceb7246b9a0a24ecbfa8f4cf2c46288 100644 (file)
@@ -644,6 +644,8 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
                                interface->control_cache.size_in_bytes,
                                (struct hpi_control_cache_info *)
                                p_control_cache_virtual);
+                       if (!phw->p_cache)
+                               err = HPI_ERROR_MEMORY_ALLOC;
                }
                if (!err) {
                        err = hpios_locked_mem_get_phys_addr(&phw->
index dda4f1c6f65847504a71016b1064d0039c65e8a3..d67f4d3db911dd9685d24e08f29d6b6bc23f16f9 100644 (file)
@@ -571,14 +571,20 @@ struct hpi_control_cache *hpi_alloc_control_cache(const u32
 {
        struct hpi_control_cache *p_cache =
                kmalloc(sizeof(*p_cache), GFP_KERNEL);
+       if (!p_cache)
+               return NULL;
+       p_cache->p_info =
+               kmalloc(sizeof(*p_cache->p_info) * number_of_controls,
+                       GFP_KERNEL);
+       if (!p_cache->p_info) {
+               kfree(p_cache);
+               return NULL;
+       }
        p_cache->cache_size_in_bytes = size_in_bytes;
        p_cache->control_count = number_of_controls;
        p_cache->p_cache =
                (struct hpi_control_cache_single *)pDSP_control_buffer;
        p_cache->init = 0;
-       p_cache->p_info =
-               kmalloc(sizeof(*p_cache->p_info) * p_cache->control_count,
-               GFP_KERNEL);
        return p_cache;
 }
 
index 3e5ca8fb519ff1ae5d2c03cf7f2beb8700b1745d..e377287192aae954aa42d153cb9931f0934f67b4 100644 (file)
@@ -225,39 +225,25 @@ struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip)
 {
        struct dsp_spos_instance * ins = kzalloc(sizeof(struct dsp_spos_instance), GFP_KERNEL);
 
-       if (ins == NULL) 
+       if (ins == NULL)
                return NULL;
 
        /* better to use vmalloc for this big table */
-       ins->symbol_table.nsymbols = 0;
        ins->symbol_table.symbols = vmalloc(sizeof(struct dsp_symbol_entry) *
                                            DSP_MAX_SYMBOLS);
-       ins->symbol_table.highest_frag_index = 0;
-
-       if (ins->symbol_table.symbols == NULL) {
+       ins->code.data = kmalloc(DSP_CODE_BYTE_SIZE, GFP_KERNEL);
+       ins->modules = kmalloc(sizeof(struct dsp_module_desc) * DSP_MAX_MODULES, GFP_KERNEL);
+       if (!ins->symbol_table.symbols || !ins->code.data || !ins->modules) {
                cs46xx_dsp_spos_destroy(chip);
                goto error;
        }
-
+       ins->symbol_table.nsymbols = 0;
+       ins->symbol_table.highest_frag_index = 0;
        ins->code.offset = 0;
        ins->code.size = 0;
-       ins->code.data = kmalloc(DSP_CODE_BYTE_SIZE, GFP_KERNEL);
-
-       if (ins->code.data == NULL) {
-               cs46xx_dsp_spos_destroy(chip);
-               goto error;
-       }
-
        ins->nscb = 0;
        ins->ntask = 0;
-
        ins->nmodules = 0;
-       ins->modules = kmalloc(sizeof(struct dsp_module_desc) * DSP_MAX_MODULES, GFP_KERNEL);
-
-       if (ins->modules == NULL) {
-               cs46xx_dsp_spos_destroy(chip);
-               goto error;
-       }
 
        /* default SPDIF input sample rate
           to 48000 khz */
@@ -271,8 +257,8 @@ struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip)
 
        /* set left and right validity bits and
           default channel status */
-       ins->spdif_csuv_default = 
-               ins->spdif_csuv_stream =  
+       ins->spdif_csuv_default =
+               ins->spdif_csuv_stream =
         /* byte 0 */  ((unsigned int)_wrap_all_bits(  (SNDRV_PCM_DEFAULT_CON_SPDIF        & 0xff)) << 24) |
         /* byte 1 */  ((unsigned int)_wrap_all_bits( ((SNDRV_PCM_DEFAULT_CON_SPDIF >> 8) & 0xff)) << 16) |
         /* byte 3 */   (unsigned int)_wrap_all_bits(  (SNDRV_PCM_DEFAULT_CON_SPDIF >> 24) & 0xff) |
@@ -281,6 +267,9 @@ struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip)
        return ins;
 
 error:
+       kfree(ins->modules);
+       kfree(ins->code.data);
+       vfree(ins->symbol_table.symbols);
        kfree(ins);
        return NULL;
 }
index 460fb2ef7e394614a4045a51d4306c429e818d6a..18af38ebf7579f5507fca391f66ba9280844ccf4 100644 (file)
@@ -1166,6 +1166,7 @@ static const char *cs420x_models[CS420X_MODELS] = {
 
 static struct snd_pci_quirk cs420x_cfg_tbl[] = {
        SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
+       SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
        SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
        SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
        SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),
index ef9af3f4ace2f6fda837a89e4ea46ff8821fd86c..1bd7a540fd49dfa64918e4d533a3d80cbb8fb4af 100644 (file)
@@ -425,7 +425,7 @@ exit:
 static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream)
 {
        struct snd_pcm_substream *substream = lx_stream->stream;
-       const int is_capture = lx_stream->is_capture;
+       const unsigned int is_capture = lx_stream->is_capture;
 
        int err;
 
@@ -473,7 +473,7 @@ static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream)
 
 static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream)
 {
-       const int is_capture = lx_stream->is_capture;
+       const unsigned int is_capture = lx_stream->is_capture;
        int err;
 
        snd_printd(LXP "stopping: stopping stream\n");
index 51afc048961d9855c39e321e523f9f526bd8acd3..aea621eafbb56799385e0e2188a5b3e1130f21d2 100644 (file)
@@ -60,7 +60,7 @@ struct lx_stream {
        snd_pcm_uframes_t          frame_pos;
        enum lx_stream_status      status; /* free, open, running, draining
                                            * pause */
-       int                        is_capture:1;
+       unsigned int               is_capture:1;
 };
 
 
index 3086b751da4a59271b497e1a8605c3664d15a2ff..617f98b0cbae47ce9c76265f50590f88a83c187d 100644 (file)
@@ -1152,7 +1152,7 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip,
                                           struct lx_stream *lx_stream)
 {
        struct snd_pcm_substream *substream = lx_stream->stream;
-       int is_capture = lx_stream->is_capture;
+       const unsigned int is_capture = lx_stream->is_capture;
        int err;
        unsigned long flags;
 
index 94a9d06b90277797215e299907444a85ca3f379a..3b5690d28b8bb080e1c6da2658f3017abcfd6f57 100644 (file)
@@ -25,8 +25,9 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
        select SND_SOC_CS42L51 if I2C
        select SND_SOC_CS4270 if I2C
+       select SND_SOC_CX20442
        select SND_SOC_DA7210 if I2C
-       select SND_SOC_JZ4740 if SOC_JZ4740
+       select SND_SOC_JZ4740_CODEC if SOC_JZ4740
        select SND_SOC_MAX98088 if I2C
        select SND_SOC_MAX9877 if I2C
        select SND_SOC_PCM3008
index d251ff54a2d36f8b691b4aca2073d74adb010673..c5ab8c8057714871e13ad249805f60877ff32f5d 100644 (file)
@@ -58,7 +58,7 @@
        (1000000000 / ((rate * 1000) / samples))
 
 #define US_TO_SAMPLES(rate, us) \
-       (rate / (1000000 / us))
+       (rate / (1000000 / (us < 1000000 ? us : 1000000)))
 
 #define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \
        ((samples * 5000) / ((burstrate * 5000) / (burstrate - playrate)))
@@ -200,7 +200,7 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg,
                      u8 *value)
 {
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
-       int val;
+       int val, ret = 0;
 
        *value = reg & 0xff;
 
@@ -210,6 +210,7 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg,
                if (val < 0) {
                        dev_err(codec->dev, "Read failed (%d)\n", val);
                        value[0] = dac33_read_reg_cache(codec, reg);
+                       ret = val;
                } else {
                        value[0] = val;
                        dac33_write_reg_cache(codec, reg, val);
@@ -218,7 +219,7 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg,
                value[0] = dac33_read_reg_cache(codec, reg);
        }
 
-       return 0;
+       return ret;
 }
 
 static int dac33_write(struct snd_soc_codec *codec, unsigned int reg,
@@ -329,13 +330,18 @@ static void dac33_init_chip(struct snd_soc_codec *codec)
                    dac33_read_reg_cache(codec, DAC33_LINER_TO_RLO_VOL));
 }
 
-static inline void dac33_read_id(struct snd_soc_codec *codec)
+static inline int dac33_read_id(struct snd_soc_codec *codec)
 {
+       int i, ret = 0;
        u8 reg;
 
-       dac33_read(codec, DAC33_DEVICE_ID_MSB, &reg);
-       dac33_read(codec, DAC33_DEVICE_ID_LSB, &reg);
-       dac33_read(codec, DAC33_DEVICE_REV_ID, &reg);
+       for (i = 0; i < 3; i++) {
+               ret = dac33_read(codec, DAC33_DEVICE_ID_MSB + i, &reg);
+               if (ret < 0)
+                       break;
+       }
+
+       return ret;
 }
 
 static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
@@ -1076,6 +1082,9 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
                /* Number of samples under i2c latency */
                dac33->alarm_threshold = US_TO_SAMPLES(rate,
                                                dac33->mode1_latency);
+               nsample_limit = DAC33_BUFFER_SIZE_SAMPLES -
+                               dac33->alarm_threshold;
+
                if (dac33->auto_fifo_config) {
                        if (period_size <= dac33->alarm_threshold)
                                /*
@@ -1086,6 +1095,8 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
                                       ((dac33->alarm_threshold / period_size) +
                                       (dac33->alarm_threshold % period_size ?
                                       1 : 0));
+                       else if (period_size > nsample_limit)
+                               dac33->nsample = nsample_limit;
                        else
                                dac33->nsample = period_size;
                } else {
@@ -1097,8 +1108,7 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
                         */
                        dac33->nsample_max = substream->runtime->buffer_size -
                                                period_size;
-                       nsample_limit = DAC33_BUFFER_SIZE_SAMPLES -
-                                       dac33->alarm_threshold;
+
                        if (dac33->nsample_max > nsample_limit)
                                dac33->nsample_max = nsample_limit;
 
@@ -1414,9 +1424,15 @@ static int dac33_soc_probe(struct snd_soc_codec *codec)
                dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
                goto err_power;
        }
-       dac33_read_id(codec);
+       ret = dac33_read_id(codec);
        dac33_hard_power(codec, 0);
 
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read chip ID: %d\n", ret);
+               ret = -ENODEV;
+               goto err_power;
+       }
+
        /* Check if the IRQ number is valid and request it */
        if (dac33->irq >= 0) {
                ret = request_irq(dac33->irq, dac33_interrupt_handler,
index 329acc1a207457942a560e86d7f990a2fc44ffd8..ee4fb201de60ca9ceb969fd00ce1292aad0a9330 100644 (file)
@@ -119,13 +119,13 @@ static int tpa6130a2_power(int power)
 {
        struct  tpa6130a2_data *data;
        u8      val;
-       int     ret;
+       int     ret = 0;
 
        BUG_ON(tpa6130a2_client == NULL);
        data = i2c_get_clientdata(tpa6130a2_client);
 
        mutex_lock(&data->mutex);
-       if (power) {
+       if (power && !data->power_state) {
                /* Power on */
                if (data->power_gpio >= 0)
                        gpio_set_value(data->power_gpio, 1);
@@ -153,7 +153,7 @@ static int tpa6130a2_power(int power)
                val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
                val &= ~TPA6130A2_SWS;
                tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
-       } else {
+       } else if (!power && data->power_state) {
                /* set SWS */
                val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
                val |= TPA6130A2_SWS;
index b4f11724a63ffc771c1a1d83909e31ae5cccaab7..aca4b1ea10bb710cd733ea730d22171895df620e 100644 (file)
@@ -186,7 +186,6 @@ static int wm8900_volatile_register(unsigned int reg)
 {
        switch (reg) {
        case WM8900_REG_ID:
-       case WM8900_REG_POWER1:
                return 1;
        default:
                return 0;
@@ -1200,11 +1199,6 @@ static int wm8900_probe(struct snd_soc_codec *codec)
                return -ENODEV;
        }
 
-       /* Read back from the chip */
-       reg = snd_soc_read(codec, WM8900_REG_POWER1);
-       reg = (reg >> 12) & 0xf;
-       dev_info(codec->dev, "WM8900 revision %d\n", reg);
-
        wm8900_reset(codec);
 
        /* Turn the chip on */
index 2cb81538cd9194c9cc278515171d67a45ac39ca6..19ca782ac970f1956243862534e5df1df12a3113 100644 (file)
@@ -123,7 +123,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
                        reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
                        break;
                default:
-                       WARN(1, "Unknown DCS readback method");
+                       WARN(1, "Unknown DCS readback method\n");
                        break;
                }
 
index a3bfb2e8b70fb6946739837126dc49fed237f658..73d0edd8ded9de053db82b27c60433fe1a7b8686 100644 (file)
@@ -79,7 +79,7 @@ static void tosa_ext_control(struct snd_soc_codec *codec)
 static int tosa_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* check the jack status at stream startup */
        tosa_ext_control(codec);
index 1c8f3f507f54e7d1fc469ff03a2fdbf787640e3a..614a8b30d87bdefdb99414f06d1d74438e60cd18 100644 (file)
@@ -165,8 +165,11 @@ static ssize_t pmdown_time_set(struct device *dev,
 {
        struct snd_soc_pcm_runtime *rtd =
                        container_of(dev, struct snd_soc_pcm_runtime, dev);
+       int ret;
 
-       strict_strtol(buf, 10, &rtd->pmdown_time);
+       ret = strict_strtol(buf, 10, &rtd->pmdown_time);
+       if (ret)
+               return ret;
 
        return count;
 }
index 7dae05d8783e4274266bb5c867e534b342e18614..782f741cd00a4e3bb97317d05827f8c3134299bc 100644 (file)
@@ -60,7 +60,7 @@ static const struct rc_config {
        { USB_ID(0x041e, 0x3000), 0, 1, 2, 1,  18, 0x0013 }, /* Extigy       */
        { USB_ID(0x041e, 0x3020), 2, 1, 6, 6,  18, 0x0013 }, /* Audigy 2 NX  */
        { USB_ID(0x041e, 0x3040), 2, 2, 6, 6,  2,  0x6e91 }, /* Live! 24-bit */
-       { USB_ID(0x041e, 0x3042), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi */
+       { USB_ID(0x041e, 0x3042), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi S51 */
        { USB_ID(0x041e, 0x3048), 2, 2, 6, 6,  2,  0x6e91 }, /* Toshiba SB0500 */
 };
 
@@ -183,7 +183,13 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        if (value > 1)
                return -EINVAL;
        changed = value != mixer->audigy2nx_leds[index];
-       err = snd_usb_ctl_msg(mixer->chip->dev,
+       if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042))
+               err = snd_usb_ctl_msg(mixer->chip->dev,
+                             usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+                             !value, 0, NULL, 0, 100);
+       else
+               err = snd_usb_ctl_msg(mixer->chip->dev,
                              usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
                              value, index + 2, NULL, 0, 100);
@@ -225,8 +231,12 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
        int i, err;
 
        for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) {
+               /* USB X-Fi S51 doesn't have a CMSS LED */
+               if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0)
+                       continue;
                if (i > 1 && /* Live24ext has 2 LEDs only */
                        (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
+                        mixer->chip->usb_id == USB_ID(0x041e, 0x3042) ||
                         mixer->chip->usb_id == USB_ID(0x041e, 0x3048)))
                        break; 
                err = snd_ctl_add(mixer->chip->card,
@@ -365,6 +375,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 
        if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) ||
            mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
+           mixer->chip->usb_id == USB_ID(0x041e, 0x3042) ||
            mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) {
                if ((err = snd_audigy2nx_controls_create(mixer)) < 0)
                        return err;
index cff3a3c465d736f17d73a4cf6c01c54c936469c3..4132522ac90f8c88da831b68f9cbdf777131de8e 100644 (file)
@@ -676,8 +676,10 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
        if (!needs_knot)
                return 0;
 
-       subs->rate_list.count = count;
        subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL);
+       if (!subs->rate_list.list)
+               return -ENOMEM;
+       subs->rate_list.count = count;
        subs->rate_list.mask = 0;
        count = 0;
        list_for_each_entry(fp, &subs->fmt_list, list) {
index b9efed5e35cc222f3e7b34d922bbc1b90b29987b..792a750d9441af80cd16e4d797234159875babc4 100644 (file)
@@ -30,8 +30,8 @@ __irf_end:
 .section .init.ramfs.info,"a"
 .globl __initramfs_size
 __initramfs_size:
-#ifdef CONFIG_32BIT
-       .long __irf_end - __irf_start
-#else
+#ifdef CONFIG_64BIT
        .quad __irf_end - __irf_start
+#else
+       .long __irf_end - __irf_start
 #endif