From afcf71d6133eb433d56d38582125f934977f7466 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:11:01 -0500 Subject: [PATCH] Import pre2.0.6 --- CREDITS | 18 + Documentation/Changes | 6 +- Documentation/Configure.help | 378 +-- Documentation/cdrom/aztcd | 4 +- Documentation/cdrom/cdrom-standard.tex | 2 +- Documentation/cdrom/ide-cd | 22 +- Documentation/filesystems/affs.txt | 51 +- Documentation/isdn/INTERFACE | 53 +- Documentation/isdn/README | 51 +- Documentation/isdn/README.icn | 5 +- Documentation/isdn/README.syncppp | 9 +- Documentation/isdn/syncPPP.FAQ | 232 +- Makefile | 2 +- arch/alpha/defconfig | 11 +- arch/alpha/kernel/traps.c | 131 +- arch/i386/boot/video.S | 2 +- arch/i386/defconfig | 10 +- arch/m68k/kernel/head.S | 2 +- drivers/block/genhd.c | 19 +- drivers/block/ide-cd.c | 27 +- drivers/block/ll_rw_blk.c | 16 +- drivers/cdrom/aztcd.c | 35 +- drivers/cdrom/mcdx.c | 26 +- drivers/char/README.baycom | 2 +- drivers/char/pcxx.c | 6 + drivers/isdn/Config.in | 3 +- drivers/isdn/Makefile | 6 + drivers/isdn/icn/icn.c | 2455 +++++++++-------- drivers/isdn/icn/icn.h | 284 +- drivers/isdn/isdn_audio.c | 428 +++ drivers/isdn/isdn_audio.h | 43 + drivers/isdn/isdn_common.c | 585 ++-- drivers/isdn/isdn_common.h | 1 - drivers/isdn/isdn_net.c | 134 +- drivers/isdn/isdn_ppp.c | 327 ++- drivers/isdn/isdn_ppp.h | 9 +- drivers/isdn/isdn_tty.c | 2111 ++++++++------ drivers/isdn/isdn_tty.h | 20 +- drivers/isdn/pcbit/drv.c | 15 +- drivers/isdn/teles/buffers.c | 7 +- drivers/isdn/teles/callc.c | 67 +- drivers/isdn/teles/card.c | 281 +- drivers/isdn/teles/fsm.c | 5 +- drivers/isdn/teles/isdnl2.c | 150 +- drivers/isdn/teles/isdnl3.c | 62 +- drivers/isdn/teles/l3_1TR6.c | 207 +- drivers/isdn/teles/l3_1TR6.h | 82 +- drivers/isdn/teles/llglue.c | 11 +- drivers/isdn/teles/q931.c | 470 +++- drivers/isdn/teles/teles.h | 6 +- drivers/net/8390.c | 2 +- drivers/net/dummy.c | 5 +- drivers/net/loopback.c | 3 + drivers/net/plip.c | 1 + drivers/net/ppp.c | 1 + drivers/net/sdla.c | 2 +- drivers/net/slhc.c | 12 +- drivers/scsi/Config.in | 7 +- drivers/scsi/Makefile | 18 +- .../scsi/{README.qlogic => README.qlogicfas} | 20 +- drivers/scsi/README.qlogicisp | 26 + drivers/scsi/atari_NCR5380.c | 2 +- drivers/scsi/atari_scsi.h | 2 +- drivers/scsi/constants.c | 56 +- drivers/scsi/hosts.c | 15 +- drivers/scsi/hosts.h | 2 +- drivers/scsi/qlogic.h | 40 - drivers/scsi/{qlogic.c => qlogicfas.c} | 37 +- drivers/scsi/qlogicfas.h | 43 + drivers/scsi/qlogicisp.c | 1599 +++++++++++ drivers/scsi/qlogicisp.h | 82 + drivers/scsi/qlogicisp_asm.c | 1273 +++++++++ drivers/scsi/scsi.h | 2 +- drivers/scsi/scsi_ioctl.c | 2 +- drivers/scsi/sd.c | 21 +- drivers/scsi/sr_ioctl.c | 27 +- drivers/scsi/st.c | 33 +- fs/Config.in | 9 +- fs/affs/amigaffs.c | 58 +- fs/affs/bitmap.c | 271 +- fs/affs/dir.c | 25 +- fs/affs/file.c | 93 +- fs/affs/inode.c | 189 +- fs/affs/namei.c | 16 +- fs/affs/symlink.c | 2 +- fs/buffer.c | 2 + fs/isofs/rock.c | 4 +- include/asm-alpha/unaligned.h | 82 +- include/asm-generic/unaligned.h | 20 + include/asm-i386/unaligned.h | 16 + include/linux/affs_fs.h | 32 +- include/linux/affs_fs_i.h | 25 +- include/linux/affs_fs_sb.h | 31 +- include/linux/affs_hardblocks.h | 4 - include/linux/amigaffs.h | 124 +- include/linux/aztcd.h | 10 +- include/linux/isdn.h | 129 +- include/linux/isdn_ppp.h | 5 + include/linux/isdnif.h | 49 +- include/linux/mcdx.h | 10 +- include/linux/proc_fs.h | 3 +- include/net/sock.h | 30 +- kernel/module.c | 2 +- net/core/net_alias.c | 14 + net/decnet/README | 2 +- net/ipv4/tcp_input.c | 12 +- net/ipv4/tcp_output.c | 2 +- 107 files changed, 9415 insertions(+), 4078 deletions(-) create mode 100644 drivers/isdn/isdn_audio.c create mode 100644 drivers/isdn/isdn_audio.h rename drivers/scsi/{README.qlogic => README.qlogicfas} (82%) create mode 100644 drivers/scsi/README.qlogicisp delete mode 100644 drivers/scsi/qlogic.h rename drivers/scsi/{qlogic.c => qlogicfas.c} (95%) create mode 100644 drivers/scsi/qlogicfas.h create mode 100644 drivers/scsi/qlogicisp.c create mode 100644 drivers/scsi/qlogicisp.h create mode 100644 drivers/scsi/qlogicisp_asm.c create mode 100644 include/asm-generic/unaligned.h create mode 100644 include/asm-i386/unaligned.h diff --git a/CREDITS b/CREDITS index 6244be2ea7ae..ca74bb5abbb8 100644 --- a/CREDITS +++ b/CREDITS @@ -434,6 +434,15 @@ N: Philip Gladstone E: philipg@onsett.com D: Kernel / timekeeping stuff +N: Michael A. Griffith +E: grif@cs.ucr.edu +W: http://www.cs.ucr.edu/~grif +D: Loopback speedup, qlogic scsi hacking, VT_LOCKSWITCH +S: Department of Computer Science +S: University of California, Riverside +S: Riverside, CA 92521-0304 +S: USA + N: Dmitry S. Gorodchanin E: begemot@bgm.rosprint.net D: RISCom/8 driver, misc kernel fixes. @@ -1270,8 +1279,10 @@ S: USA N: Stephen Tweedie E: sct@dcs.ed.ac.uk +P: 1024/E7A417AD E2 FE A4 20 34 EC ED FC 7D 7E 67 8D E0 31 D1 69 D: Second extended file system developer D: General filesystem hacker +D: kswap vm management code S: Dept. of Computer Science S: University of Edinburgh S: JCMB, The King's Buildings @@ -1350,6 +1361,13 @@ S: Roger Maris Cancer Center S: 820 4th St. N. S: Fargo, ND 58122 +N: Hans-Joachim Widmaier +E: jbhr@sofal.tynet.sub.org +D: AFFS rewrite +S: Eichenweg 16 +S: 73650 Winterbach +S: Germany + N: Marco van Wieringen E: mvw@mercury.mcs.nl.mugnet.org D: Author of acct and quota diff --git a/Documentation/Changes b/Documentation/Changes index b4c8a0933e7a..0b6775088b8a 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -324,8 +324,8 @@ throughout 1.3.x. A warning will be printed in 2.0.x when the old numbers are used, and their use will be discontinued entirely in 2.1.x In order to avoid trouble, you need to recompile any programs that -emit floppy ioctls. These include mtools and fdutils. You can get -mtools at: +emit floppy ioctls. These include mtools, fdutils and dosemu. You can +get mtools at: ftp://ftp.imag.fr/pub/Linux/ZLIBC/mtools/mtools-3.0.src.tar.gz ftp://sunsite.unc.edu/pub/Linux/utils/disk-management/mtools-3.0.src.tar.gz @@ -337,6 +337,8 @@ ftp://ftp.imag.fr/pub/Linux/ZLIBC/fdutils/fdutils-4.3.src.tar.gz ftp://sunsite.unc.edu/pub/Linux/system/Misc/fdutils-4.3.src.tar.gz ftp://tsx-11.mit.edu/pub/linux/sources/sbin/fdutils-4.3.src.tar.gz + For dosemu, see above. + In the future, the ioctl used by fdformat might be discontinued altogether. Please use superformat (included in fdutils) instead. diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 93ceacaecb0e..f3650f7fab34 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -1,8 +1,7 @@ # Maintained by Axel Boldt (boldt@math.ucsb.edu) # # This version of the Linux kernel configuration help texts -# corresponds to the kernel versions 1.3.x. Be aware that these -# are development kernels. +# corresponds to the kernel versions 2.0.x. # # Information about what a kernel is, what it does, how to patch and # compile it and much more is contained in the Kernel-HOWTO, available @@ -45,7 +44,6 @@ CONFIG_EXPERIMENTAL may not meet the normal level of reliability or it may fail to work in some special cases. Detailed bug reports from people familiar with the kernel internals are usually welcomed by the developers. - Unless you intend to help test and develop a feature or driver that falls into this category, or you have a situation that requires using these features you should probably say N here, which will cause this @@ -128,7 +126,7 @@ CONFIG_BLK_DEV_IDE interfaces, for a combination of up to eight IDE disk/cdrom/tape drives. Useful information about large (>540MB) IDE disks, soundcard IDE ports, and other topics, is all contained in - drivers/block/README.ide. If you have one or more IDE drives, say Y + Documentation/ide.txt. If you have one or more IDE drives, say Y here. If your system has no IDE drives, or if memory requirements are really tight, you could say N here, and select the Old harddisk driver instead to save about 13kB of memory in the kernel. To @@ -156,11 +154,13 @@ CONFIG_BLK_DEV_HD_IDE the new enhanced driver by itself. This option installs the old harddisk driver to control the primary IDE/disk interface in the system, leaving the new enhanced IDE driver take care of only the - 2nd/3rd/4th IDE interfaces. Choosing this option may be useful for - older systems which have MFM/RLL/ESDI controller+drives at the - primary port address (0x1f0), along with IDE drives at the - secondary/3rd/4th port addresses. Normally, just say N here; you - will then use the new driver for all 4 interfaces. + 2nd/3rd/4th IDE interfaces. Doing this will prevent you from having + an IDE/ATAPI CDROM or tape drive connected to the primary IDE + interface. Choosing this option may be useful for older systems + which have MFM/RLL/ESDI controller+drives at the primary port + address (0x1f0), along with IDE drives at the secondary/3rd/4th port + addresses. Normally, just say N here; you will then use the new + driver for all 4 interfaces. Include IDE/ATAPI CDROM support CONFIG_BLK_DEV_IDECD @@ -174,9 +174,10 @@ CONFIG_BLK_DEV_IDECD If this is your only CDROM drive, you can say N to all other CDROM options, but be sure to say Y to the ISO9660 filesystem. Read the CDROM-HOWTO, available via ftp (user: anonymous) in - sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that older versions of - lilo (the linux boot loader) cannot properly deal with IDE/ATAPI - CDROMs, so install lilo-16 or higher, available from + sunsite.unc.edu:/pub/Linux/docs/HOWTO and the file + Documentation/cdrom/ide-cd. Note that older versions of lilo (the + linux boot loader) cannot properly deal with IDE/ATAPI CDROMs, so + install lilo-16 or higher, available from sunsite.unc.edu:/pub/Linux/system/Linux-boot/lilo. Include IDE/ATAPI TAPE support @@ -186,7 +187,7 @@ CONFIG_BLK_DEV_IDETAPE similar to the SCSI protocol. At boot time, the TAPE drive will be identified along with other IDE devices, as "hdb" or "hdc", or something similar. Be sure to consult the drivers/block/ide-tape.c - and README.ide files for usage information. + and Documentation/ide.txt files for usage information. Support removable IDE interfaces (PCMCIA) CONFIG_BLK_DEV_IDE_PCMCIA @@ -278,8 +279,12 @@ CONFIG_BLK_DEV_PROMISE XT harddisk support CONFIG_BLK_DEV_XD - Very old 8 bit hard disk controllers used in the IBM XT - computer. Pretty unlikely that you have this: say N. + Very old 8 bit hard disk controllers used in the IBM XT computer. To + include a driver for these, say Y. If you want to compile the driver + as a module ( = code which can be inserted in and removed from the + running kernel whenever you want), say M here and read + Documentation/modules.txt. It's pretty unlikely that you have one of + these: say N. Multiple devices driver support CONFIG_BLK_DEV_MD @@ -390,15 +395,15 @@ CONFIG_NET Network aliasing CONFIG_NET_ALIAS - This is for setting several network addresses on the same low-level + This is for setting multiple IP addresses on the same low-level network device driver. Typically used for services that act - differently based on the address they listen on (e.g. Apache httpd) - or for connecting to different logical networks through the same - physical interface. This is the generic part, later when - configuring network protocol options you will be asked for - protocol-specific aliasing support. See + differently based on the address they listen on (e.g. "multihosting" + on Apache httpd) or for connecting to different logical networks + through the same physical interface. This is the generic part, + later when configuring network protocol options you will be asked + for protocol-specific aliasing support. See Documentation/networking/alias.txt for more info. If you need this - features (for any protocol, like IP) say Y; if unsure, say N. + feature (for any protocol, like IP) say Y; if unsure, say N. Network firewalls CONFIG_FIREWALL @@ -407,8 +412,16 @@ CONFIG_FIREWALL net is inspected by the firewall first. If you want to configure your Linux box as a firewall for a local network, say Y here. If your local network is TCP/IP based, you will have to say Y to "IP: - firewalling", below. Chances are that you should use this on any - machine being run as a router and not on a host. + firewalling", below. You also need to say Y here and enable "IP + firewalling" below in order to be able to use IP masquerading + (i.e. local computers can chat with an outside host, but that + outside host is made to think that it is talking to the firewall + box. Makes the local network completely invisible and avoids the + need to allocate valid IP host addresses for the machines on the + local net) or to use the ip packet accounting to see what is using + all your network bandwidth. Chances are that you should use this on + any machine being run as a router and not on a host. If unsure, say + N. Sun floppy controller support CONFIG_BLK_DEV_SUNFD @@ -512,8 +525,9 @@ CONFIG_PCI Find out whether you have a PCI motherboard. PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside your box. Other bus systems are ISA, EISA, Microchannel (MCA) or - VESA. If you have PCI, say Y, otherwise N. Note1: MCA systems are - not supported by the standard kernels, but patches exist at + VESA. If you have PCI, say Y, otherwise N. Note1: MCA systems + (notably some IBM PS/2's) are not supported by the standard kernels, + but patches exist at http://www.undergrad.math.uwaterloo.ca/~cpbeaure/mca-linux.html on the WWW. Note2: some old PCI motherboards have BIOS bugs and may crash if "PCI bios support" is enabled (but they run fine without @@ -615,19 +629,26 @@ CONFIG_BINFMT_AOUT Kernel support for JAVA binaries CONFIG_BINFMT_JAVA - JAVA binaries are becoming a universal executable format. This - option allows Java binaries and Java Applets to be handled invisibly - to the OS. As more and more Java programs become available, the use - for this will gradually increase. If you want to use this, read the - Java on Linux HOWTO, available via ftp (user: anonymous) at - sunsite.unc.edu:/pub/Linux/docs/HOWTO. In order to execute Java binaries, - you will also need to install the Java Developers Kit. If you disable - this option it will reduce your kernel by about one page. This is not - much and by itself does not warrant removing support. However its - removal is a good idea if you do not have the JDK installed. If you - don't know what to answer at this point then answer Y. You may answer - M for module support and later load the module when you install the - JDK or find a interesting Java program that you can't live without. + JAVA is an object oriented programming language developed by SUN; + JAVA programs are compiled into "JAVA bytecode" which can then be + interpreted by run time systems on many different operating systems. + These JAVA binaries are becoming a universal executable format. This + option allows you to run a Java binary just like any other Linux + program: by typing in its name. As more and more Java programs + become available, the use for this will gradually increase. You can + even execute HTML files containing JAVA applets (= JAVA binaries) if + those files start with the string "". If you want to + use this, read Documentation/java.txt and the Java on Linux HOWTO, + available via ftp (user: anonymous) at + sunsite.unc.edu:/pub/Linux/docs/HOWTO. You will then need to install + the run time system contained in the Java Developers Kit (JDK) as + described in the HOWTO. If you disable this option it will reduce + your kernel by about 4kB. This is not much and by itself does not + warrant removing support. However its removal is a good idea if you + do not have the JDK installed. If you don't know what to answer at + this point then answer Y. You may answer M for module support and + later load the module when you install the JDK or find a interesting + Java program that you can't live without. Processor type CONFIG_M386 @@ -704,25 +725,23 @@ CONFIG_KERNELD available via ftp (user: anonymous) from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If unsure, say Y. -ARP daemon support +ARP daemon support (EXPERIMENTAL) CONFIG_ARPD Normally, the kernel maintains an internal cache which maps IP addresses to hardware addresses on the local network, so that - Ethernet/Token Ring/ etc. frames are sent to the proper address - on the physical networking layer. For small networks having - a few hundred directly connected hosts or less, keeping this - address resolution cache (ARP) inside the kernel works well. - However, maintaining an internal ARP cache does not work well for - very large switched networks, and will use a lot of kernel memory - if TCP/IP connections are made to many machines on the network. - By enabling this option, the kernel's internal ARP cache will - never grow to more than 256 entries (the oldest entries are - expired in a LIFO manner) and communication will be attempted - with an external ARP daemon, arpd, via the kerneld message - queue. This code is still experimental. If you do enable - arpd support, you should obtain a copy of arpd from - http://www.loran.com/~layes/arpd/index.html. If unsure, - say N. + Ethernet/Token Ring/ etc. frames are sent to the proper address on + the physical networking layer. For small networks having a few + hundred directly connected hosts or less, keeping this address + resolution (ARP) cache inside the kernel works well. However, + maintaining an internal ARP cache does not work well for very large + switched networks, and will use a lot of kernel memory if TCP/IP + connections are made to many machines on the network. By enabling + this option, the kernel's internal ARP cache will never grow to more + than 256 entries (the oldest entries are expired in a LIFO manner) + and communication will be attempted with an external ARP daemon, + arpd. This code is still experimental. If you do enable arpd + support, you should obtain a copy of arpd from + http://www.loran.com/~layes/arpd/index.html. If unsure, say N. TCP/IP networking CONFIG_INET @@ -778,9 +797,9 @@ IP: multicasting CONFIG_IP_MULTICAST This is code for addressing several networked computers at once, enlarging your kernel by about 2 kB. If you are using gated, the - to update your computer's routing tables and are using RIP2 or OSPF - you will need to have this option compiled in. You also need - multicasting if you intend to participate in the MBONE, a high + daemon that updates your computer's routing tables, and are using + RIP2 or OSPF you will need to have this option compiled in. You also + need multicasting if you intend to participate in the MBONE, a high bandwidth network on top of the internet which carries audio and video broadcasts. More information about the MBONE is on the WWW at http://www.best.com/~prince/techinfo/mbone.html (to browse the WWW, @@ -799,17 +818,19 @@ CONFIG_IP_ROUTER IP: firewalling CONFIG_IP_FIREWALL - If you want to configure your Linux box as a firewall for a local + If you want to configure your Linux box as a firewall for a local TCP/IP based network, say Y here. This will enlarge your kernel by about 2kB. You may need to read the FIREWALL-HOWTO, available via - ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also, - you will need the ipfwadm tool to allow selective blocking of internet - traffic based on type, origin and destination. You need to enable IP - firewalling in order to be able to use IP masquerading (i.e. local - computers can chat with an outside host, but that outside host is - made to think that it is talking to the firewall box. Makes the local - network completely invisible) or to use the ip packet accounting to see - what is using all your network bandwidth. + ftp (user: anonymous) in + sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also, you will need the + ipfwadm tool to allow selective blocking of internet traffic based + on type, origin and destination. You need to enable IP firewalling + in order to be able to use IP masquerading (i.e. local computers can + chat with an outside host, but that outside host is made to think + that it is talking to the firewall box. Makes the local network + completely invisible and avoids the need to allocate valid IP host + addresses for the machines on the local net) or to use the ip packet + accounting to see what is using all your network bandwidth. IP: accounting CONFIG_IP_ACCT @@ -882,7 +903,7 @@ CONFIG_IP_ALIAS syntax explained in Documentation/networking/alias.txt. If you want this, say Y. Most people don't need it and say N. -IP: multicast routing(in progress) +IP: multicast routing (EXPERIMENTAL) CONFIG_IP_MROUTE This is used if you want your machine to act as a router for IP packets that have several destination addresses. It is needed on the @@ -1041,11 +1062,11 @@ CONFIG_AX25 use a low speed TNC (a Terminal Node Controller acts as a kind of modem connecting your computer's serial port to your radio's microphone input and speaker output) supporting the KISS protocol or - the various SCC cards that are supported by the Ottowa PI, the + the various SCC cards that are supported by the Ottawa PI, the Gracilis Packetwin and the generic Z8530 driver. At the moment there is no driver for the Baycom modem serial and parallel port hacks although one is being written (see the HAM-HOWTO). The other - baycom cards (SCC) are supported by the Z8530 driver. + Baycom cards (SCC) are supported by the Z8530 driver. In order to use AX.25, you need to get a set of all the software for Linux amateur radio users as well as information about how to configure an AX.25 port is contained in the HAM-HOWTO, available via @@ -1083,19 +1104,21 @@ CONFIG_BPQETHER Bridging (EXPERIMENTAL) CONFIG_BRIDGE - If you enable this, your Linux box will be able to act as an + If you say Y here, then your Linux box will be able to act as an ethernet bridge, which means that the different ethernet segments it is connected to will appear as one ethernet to the participants. Several such bridges can work together to create even larger networks of ethernets using the IEEE802.1 spanning tree - algorithm. As this is a standard Linux bridges will interwork properly - with other third party bridge products. Note that if your box acts as - a bridge, it probably contains several ethernet devices, but the kernel - is not able to recognize more than one at boot time without help; for - details read the Multiple-Ethernet-mini-HOWTO, available via ftp (user: - anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. The - Bridging code is still in test. If unsure, say N. - The bridge configuration tools are available via ftp from shadow.cabi.net. + algorithm. As this is a standard, Linux bridges will interwork + properly with other third party bridge products. In order to use + this, you'll need the bridge configuration tools available via ftp + (user: anonymous) from shadow.cabi.net. Note that if your box acts + as a bridge, it probably contains several ethernet devices, but the + kernel is not able to recognize more than one at boot time without + help; for details read the Multiple-Ethernet-mini-HOWTO, available + via ftp (user: anonymous) in + sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. The Bridging code is + still in test. If unsure, say N. Kernel/User network link driver(ALPHA) CONFIG_NETLINK @@ -1107,6 +1130,10 @@ CONFIG_NETLINK messages", below. Say Y if you want to experiment with it; this is ALPHA code, which means that it need not be completely stable; it has nothing to do with the computer architecture of the same name. + You need to include this if you want to use arpd, a daemon that + helps keep the internal ARP cache (a mapping between IP addresses + and hardware addresses on the local network) small. If unsure, say + N. Routing messages CONFIG_RTNETLINK @@ -1375,9 +1402,14 @@ CONFIG_SCSI_NCR53C7xx_FAST allow DISCONNECT CONFIG_SCSI_NCR53C7xx_DISCONNECT -### -### Dunno -### + This enables the disconnect/reconnect feature of the NCR SCSI controller. + When this is enabled, a slow SCSI device will not lock the SCSI bus + while processing a request, allowing simultaneous use of e.g. a SCSI + hard disk and SCSI tape or CD-ROM drive, and providing much better + performance when using slow and fast SCSI devices at the same time. Some + devices, however, do not operate properly with this option enabled, and + will cause your SCSI system to hang, which might cause a system crash. + The safe answer therefore is to say N. Always IN2000 SCSI support CONFIG_SCSI_IN2000 @@ -1523,22 +1555,33 @@ CONFIG_NETDEVICES read Olaf Kirch's excellent book "Network Administrator's Guide", to be found in sunsite.unc.edu:/pub/Linux/docs/LDP. If unsure, say Y. +CONFIG_NET_ETHERNET + Ethernet is the most common protocol used on Local Area Networks + (LANs) in universities or companies. 10-base-2 and 10-base-T and + 100-base- are common types of ethernet. If your Linux + machine will be connected to an Ethernet and you have an ethernet + network card installed in your computer, say Y here and read the + Ethernet-HOWTO, available via ftp (user: anonymous) from + sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the answer to this + question won't directly affect the kernel: saying N will just cause + this configure script to skip all the questions about Ethernet + network cards. If unsure, say N. + Dummy net driver support CONFIG_DUMMY - This is essentially a bit-bucket device (i.e. traffic you send to + This is essentially a bit-bucket device (i.e. traffic you send to this device is consigned into oblivion) with a configurable IP - address different from the usual 127.0.0.1. It is most commonly used - in order to make your currently inactive SLIP address seem like a - real address for local programs. If you use SLIP or PPP, you might - want to enable it. Read about it in the Network Administrator's - Guide, available via ftp (user: anonymous) from - sunsite.unc.edu:/pub/Linux/docs/LDP. Since this thing comes often - handy, the default is Y. It won't enlarge your kernel either. What a - deal. If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read Documentation/modules.txt. If you want to use - more than one dummy device at a time, you need to compile it as a - module. + address. It is most commonly used in order to make your currently + inactive SLIP address seem like a real address for local + programs. If you use SLIP or PPP, you might want to enable it. Read + about it in the Network Administrator's Guide, available via ftp + (user: anonymous) from sunsite.unc.edu:/pub/Linux/docs/LDP. Since + this thing comes often handy, the default is Y. It won't enlarge + your kernel either. What a deal. If you want to compile this as a + module ( = code which can be inserted in and removed from the + running kernel whenever you want), say M here and read + Documentation/modules.txt. If you want to use more than one dummy + device at a time, you need to compile it as a module. SLIP (serial line) support CONFIG_SLIP @@ -1588,17 +1631,23 @@ CONFIG_SLIP_SMART Six bit SLIP encapsulation CONFIG_SLIP_MODE_SLIP6 - Just occasionally you may need to run IP over hostile serial networks that - don't pass all control characters or are only seven bit. This adds an - extra mode you can use with SLIP "slip6" which contains only the normal - ascii symbols. Its good enough, for example, to run IP over the async - ports of a Camtec JNT Pad. + Just occasionally you may need to run IP over hostile serial + networks that don't pass all control characters or are only seven + bit. Saying Y here adds an extra mode you can use with SLIP: + "slip6". In this mode, SLIP will only send normal ascii symbols over + the serial device. Naturally, this has to be supported at the other + end of the link as well. It's good enough, for example, to run IP + over the async ports of a Camtec JNT Pad. If unsure, say N. Radio network interfaces CONFIG_NET_RADIO - Radio based interfaces for Linux. Both amateur radio (AX.25) and other - systems. In addition shadow.cabi.net carries user mode drivers for the - Scarab devices. These need no kernel support. + Radio based interfaces for Linux. This includes amateur radio + (AX.25), support for wireless ethernet and other systems. Note that + the answer to this question won't directly affect the kernel: + saying N will just cause this configure script to skip all the + questions about radio interfaces. Some user-level drivers for scarab + devices which don't require special kernel support are available via + ftp (user: anonymous) from shadow.cabi.net. If unsure, say N. PPP (point-to-point) support CONFIG_PPP @@ -1654,17 +1703,20 @@ CONFIG_STRIP WIC (Radio IP bridge) CONFIG_WIC Support for the WIC parallel port radio bridge. You'll probably want - to say N. + to say N. If you want to compile this driver as a module though ( = + code which can be inserted in and removed from the running kernel + whenever you want), say M here and read Documentation/modules.txt. Z8530 SCC kiss emulation driver for AX.25 CONFIG_SCC These cards are used to connect your Linux box to an amateur radio - and communicate with other computers. If you want to use this, read - Documentation/networking/z8530drv.txt and the HAM-HOWTO, available - via ftp (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read Documentation/modules.txt. + in order to communicate with other computers. If you want to use + this, read Documentation/networking/z8530drv.txt and the HAM-HOWTO, + available via ftp (user: anonymous) at + sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you want to compile this + as a module ( = code which can be inserted in and removed from the + running kernel whenever you want), say M here and read + Documentation/modules.txt. BAYCOM ser12 and par96 kiss emulation driver for AX.25 CONFIG_BAYCOM @@ -1688,11 +1740,11 @@ CONFIG_PLIP on bidirectional parallel ports only, which can transmit 8 bits at a time (you can find the wiring of these cables in drivers/net/README?.plip). The cables can be up to 15m long. This - works also if one of the machines runs DOS and has some PLIP + works also if one of the machines runs DOS/Windows and has some PLIP software installed, e.g. the Crynwr PLIP packet driver (http://sunsite.cnam.fr/packages/Telnet/PC/msdos/misc/pktdrvr.txt) - and NCSA's telnet. If you want to use this, say Y and read the PLIP - mini-HOWTO, available via ftp (user: anonymous) in + and winsock or NCSA's telnet. If you want to use this, say Y and + read the PLIP mini-HOWTO, available via ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini as well as the NET-2-HOWTO in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the PLIP protocol was changed and this PLIP driver won't work together @@ -1776,10 +1828,6 @@ CONFIG_SDLA from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. -Ethernet (10 or 100Mbit) -CONFIG_NET_ETHERNET - Say yes if you want to select support for ethernet cards. - Sun LANCE Ethernet support CONFIG_SUN_LANCE This is support for lance ethernet cards on Sun workstations such as @@ -2577,15 +2625,7 @@ CONFIG_QUOTA use it. Probably this is only useful for multi user systems. If unsure, say N. -Mandatory lock support -CONFIG_LOCK_MANDATORY - Mandatory locking is used by some System 5 style database applications. - To use this option safely you must have newer NFS daemons, new samba, - new netatalk, new mars-nwe and other file servers. At the time of - writing none of these are available. Unless you need this feature say - N. - -Standard (minix) fs support +Minix fs support CONFIG_MINIX_FS Minix is a simple operating system used in many classes about OS's. The minix filesystem (= method to organize files on a harddisk @@ -2916,23 +2956,23 @@ CONFIG_NCP_FS removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. -Amiga FFS filesystem support (read only) +Amiga FFS filesystem support (EXPERIMENTAL) CONFIG_AFFS_FS The Fast File System (FFS) is the common filesystem used on harddisks by Amiga (tm) Systems since AmigaOS Version 1.3 (34.20). It's also possible to mount diskfiles used by the Un*X Amiga Emulator by Bernd Schmidt (http://www-users.informatik.rwth-aachen.de/~crux/uae.html) If you want to do the latter, you will also need the loop device - support. Because it's in an early development state, the AFFS is - read only. Say Y if you want to be able to read files from an Amiga - FFS partition of your harddrive. Amiga floppies however cannot be - read with this driver due to an incompatibility of the floppy - controller used in an Amiga and the standard floppy controller in - PCs and workstations. Read Documentation/filesystems/affs.txt. This - filesystem is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you - want). If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say N. + support. Say Y if you want to be able to read and write files from + and to an Amiga FFS partition of your harddrive. Amiga floppies + however cannot be read with this driver due to an incompatibility of + the floppy controller used in an Amiga and the standard floppy + controller in PCs and workstations. Read + Documentation/filesystems/affs.txt. This filesystem is also available + as a module ( = code which can be inserted in and removed from the + running kernel whenever you want). If you want to compile it as a + module, say M here and read Documentation/modules.txt. + If unsure, say N. Standard/generic serial support CONFIG_SERIAL @@ -3216,11 +3256,14 @@ CONFIG_WATCHDOG result in rebooting the machine. This could be useful for a networked machine that needs to come back online as fast as possible after a lock-up. There's a watchdog implementation entirely in - software (which can sometimes fail to reboot the machine) and a driver - for hardware watchdog boards, which are more robust and can also - keep track of the temperature inside your computer. For details, - read Documentation/watchdog.txt in the kernel source. If unsure, say - N. + software (which can sometimes fail to reboot the machine) and a + driver for hardware watchdog boards, which are more robust and can + also keep track of the temperature inside your computer. For + details, read Documentation/watchdog.txt in the kernel source. If + unsure, say N. This driver is also available as a module ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. Disable watchdog shutdown on close CONFIG_WATCHDOG_NOWAYOUT @@ -3257,7 +3300,10 @@ Software Watchdog CONFIG_SOFT_WATCHDOG A software monitoring watchdog. This will fail to reboot your system from some situations that the hardware watchdog will recover - from. Equally it's a lot cheaper to install. + from. Equally it's a lot cheaper to install. This driver is also + available as a module ( = code which can be inserted in and removed + from the running kernel whenever you want). If you want to compile + it as a module, say M here and read Documentation/modules.txt. Enhanced Real Time Clock Support CONFIG_RTC @@ -3317,20 +3363,30 @@ CONFIG_PROFILE_SHIFT ISDN subsystem CONFIG_ISDN - This allows you to use an ISDN-card for networking connections and - as dialin/out device. The isdn-tty's have a built in AT-compatible - modem emulator. Network devices support autodial, channel-bundling, + ISDN ("Integrated Services Digital Networks", called RNIS in + France) is a special type of fully digital telephone line; it's + mostly used to connect to your Internet service provider (with SLIP + or PPP). The main advantage is that the speed is higher than + ordinary modem/telephone connections. It only works if your computer + is equipped with an ISDN card and both you and your service provider + purchased an ISDN line from your phone company. For details, read + http://alumni.caltech.edu/~dank/isdn/ on the WWW. (To browse the + WWW, you need to have access to a machine on the Internet that has + one of the programs lynx, netscape or Mosaic.) This driver allows + you to use an ISDN-card for networking connections and as dialin/out + device. The isdn-tty's have a built in AT-compatible modem + emulator. Network devices support autodial, channel-bundling, callback and caller-authentication without having a daemon running. A reduced T.70 protocol is supported with tty's suitable - for German BTX. Currently cards by Teles and compatibles and ICN are - supported. On D-Channel, the protocols EDSS1 and 1TR6 are + for German BTX. On D-Channel, the protocols EDSS1 and 1TR6 are supported. See Documentation/isdn/README for more information. Support synchronous PPP CONFIG_ISDN_PPP This enables synchronous PPP via ISDN. This protocol is used by - Cisco or Sun for example. You will need a special version of pppd - (called ipppd) for using this feature. See + Cisco or Sun for example. So you want say Y here if the other end of + your ISDN connection supports it. You will need a special version of + pppd (called ipppd) for using this feature. See Documentation/isdn/README.syncppp and Documentation/isdn/syncPPP.FAQ for more information. @@ -3344,11 +3400,21 @@ Use VJ-compression with synchronous PPP CONFIG_ISDN_PPP_VJ This enables Van Jacobson header compression for synchronous PPP. -ICN B1 and B2 support +Support audio via ISDN +CONFIG_ISDN_AUDIO + With this option enabled, the modem-emulator supports a subset + of the EIA Class 8 Voice commands. Using a getty with voice-support + (mgetty+sendfax by gert@greenie.muc.de with an extension, available + with the ISDN utily package for example), you will be able + to use your Linux box as an ISDN-answering machine. Of course, this + must be supported by the lowlevel driver also. Currently, the Teles + driver is the only voice-supporting one. + +ICN 2B and 4B support CONFIG_ISDN_DRV_ICN This enables support for two kinds of ISDN-cards made by a German - company called ICN. 1B is the standard version for a single ISDN - line with two B-channels, 2B supports two ISDN lines. For running + company called ICN. 2B is the standard version for a single ISDN + line with two B-channels, 4B supports two ISDN lines. For running this card, additional firmware is necessary, which has to be downloaded into the card using a utility which is distributed separately. See Documentation/isdn/README and README.icn for more @@ -3452,4 +3518,8 @@ CONFIG_AP1000 # LocalWords: Solaris RISCom riscom syncPPP PCBIT pcbit sparc anu au artoo ufs # LocalWords: hitchcock Crynwr cnam pktdrvr NCSA's CyDROM CyCDROM FreeBSD NeXT # LocalWords: NeXTstep disklabel disklabels SMD FFS tm AmigaOS diskfiles Un -# LocalWords: Bernd informatik rwth aachen uae affs +# LocalWords: Bernd informatik rwth aachen uae affs multihosting bytecode java +# LocalWords: applets applet JDK ncsa cabi SNI Alphatronix readme LANs scarab +# LocalWords: winsock RNIS caltech OSPF honour Honouring Mbit Localtalk Ottowa +# LocalWords: localtalk download Packetwin Baycom baycom interwork ascii JNT +# LocalWords: Camtec diff --git a/Documentation/cdrom/aztcd b/Documentation/cdrom/aztcd index ea7de765f64e..7ad9cc2050b6 100644 --- a/Documentation/cdrom/aztcd +++ b/Documentation/cdrom/aztcd @@ -1,10 +1,10 @@ -$Id: README.aztcd,v 2.30 1996/04/26 05:32:23 root Exp root $ +$Id: README.aztcd,v 2.50 1996/05/16 18:31:22 root Exp root $ Readme-File /usr/src/Documentation/cdrom/aztcd for AZTECH CD-ROM CDA268-01A, ORCHID CD-3110, OKANO/WEARNES CDD110, CONRAD TXC, CyCDROM CR520, CR540 CD-ROM Drives - Version 2.3 and newer + Version 2.5 and newer (for other drives see 6.-8.) NOTE: THIS DRIVER WILL WORK WITH THE CD-ROM DRIVES LISTED, WHICH HAVE diff --git a/Documentation/cdrom/cdrom-standard.tex b/Documentation/cdrom/cdrom-standard.tex index 43bbfb855101..78d887fab3ed 100644 --- a/Documentation/cdrom/cdrom-standard.tex +++ b/Documentation/cdrom/cdrom-standard.tex @@ -77,7 +77,7 @@ let the juke box work on even if a disk has fallen upon the floor and the drive door has closed without having a disk inside; without any new software layer or any structures which are not already present in \cdromh. This `other' group of \linux\ \cdrom\ driver writers -explicitely does {\em not\/} support the idea to define an additional +explicitly does {\em not\/} support the idea to define an additional software layer between driver and user program. The following text reflects the opinion of the first mentioned \linux\ diff --git a/Documentation/cdrom/ide-cd b/Documentation/cdrom/ide-cd index b543a2574960..632940cfea6a 100644 --- a/Documentation/cdrom/ide-cd +++ b/Documentation/cdrom/ide-cd @@ -1,5 +1,5 @@ IDE-CD driver documentation -10 May 1996 +19 May 1996 scott snyder 1. Introduction @@ -45,7 +45,7 @@ This driver provides the following features: --------------- 0. The ide-cd relies on the ide disk driver. See - drivers/block/README.ide for up-to-date information on the ide + Documentation/ide.txt for up-to-date information on the ide driver. 1. Make sure that the ide and ide-cd drivers are compiled into the @@ -61,7 +61,7 @@ This driver provides the following features: Depending on what type of IDE interface you have, you may need to specify additional configuration options. See - drivers/block/README.ide. + Documentation/ide.txt. 2. You should also ensure that the iso9660 filesystem is either compiled into the kernel or available as a loadable module. You @@ -81,7 +81,7 @@ This driver provides the following features: on the primary IDE interface are called `hda' and `hdb', respectively. The drives on the secondary interface are called `hdc' and `hdd'. (Interfaces at other locations get other letters - in the third position; see drivers/block/README.ide.) + in the third position; see Documentation/ide.txt.) If you want your cdrom drive to be found automatically by the driver, you should make sure your IDE interface uses either the @@ -90,7 +90,7 @@ This driver provides the following features: be jumpered as `master'. (If for some reason you cannot configure your system in this manner, you can probably still use the driver. You may have to pass extra configuration information to the kernel - when you boot, however. See drivers/block/README.ide for more + when you boot, however. See Documentation/ide.txt for more information.) 4. Boot the system. If the drive is recognized, you should see a @@ -194,7 +194,7 @@ TEST This section discusses some common problems encountered when trying to use the driver, and some possible solutions. Note that if you are experiencing problems, you should probably also review -drivers/block/README.ide for current information about the underlying +Documentation/ide.txt for current information about the underlying IDE support code. Some of these items apply only to earlier versions of the driver, but are mentioned here for completeness. @@ -204,7 +204,7 @@ from the driver. a. Drive is not detected during booting. - Review the configuration instructions above and in - drivers/block/README.ide, and check how your hardware is + Documentation/ide.txt, and check how your hardware is configured. - If your drive is the only device on an IDE interface, it should @@ -212,7 +212,7 @@ a. Drive is not detected during booting. - If your IDE interface is not at the standard addresses of 0x170 or 0x1f0, you'll need to explicitly inform the driver using a - lilo option. See drivers/block/README.ide. (This feature was + lilo option. See Documentation/ide.txt. (This feature was added around kernel version 1.3.30.) - If the autoprobing is not finding your drive, you can tell the @@ -238,7 +238,7 @@ a. Drive is not detected during booting. Support for some interfaces needing extra initialization is provided in later 1.3.x kernels. You may need to turn on additional kernel configuration options to get them to work; - see drivers/block/README.ide. + see Documentation/ide.txt. Even if support is not available for your interface, you may be able to get it to work with the following procedure. First boot @@ -283,7 +283,7 @@ c. System hangups. be worked around by specifying the `serialize' option when booting. Recent kernels should be able to detect the need for this automatically in most cases, but the detection is not - foolproof. See drivers/block/README.ide for more information + foolproof. See Documentation/ide.txt for more information about the `serialize' option and the CMD640B. - Note that many MS-DOS cdrom drivers will work with such buggy @@ -319,7 +319,7 @@ d. Can't mount a cdrom. Some early Slackware releases had these defined incorrectly. If these are wrong, you can remake them by running the script - drivers/block/MAKEDEV.ide. (You may have to make it executable + scripts/MAKEDEV.ide. (You may have to make it executable with chmod first.) If you have a /dev/cdrom symbolic link, check that it is pointing diff --git a/Documentation/filesystems/affs.txt b/Documentation/filesystems/affs.txt index 4e47d29e5de9..f561b5c87240 100644 --- a/Documentation/filesystems/affs.txt +++ b/Documentation/filesystems/affs.txt @@ -6,14 +6,12 @@ currently knows 6 different filesystems: DOS\0 The old or original filesystem, not really suited for hard disks and normally not used on them, either. - Not supported. DOS\1 The original Fast File System. Supported. DOS\2 The old "international" filesystem. International means that a bug has been fixed so that accented ("international") letters in file names are case-insensitive, as they ought to be. - Not supported. DOS\3 The "international" Fast File System. Supported. @@ -29,7 +27,10 @@ Supported block sizes are: 512, 1024, 2048 and 4096 bytes. Larger blocks speed up almost everything with the expense of wasted disk space. The speed gain above 4K seems not really worth the price, so you don't lose too much here, either. - + +The muFS (multi user File System) equivalents of the above file systems +are supported, too. + Mount options for the AFFS ========================== @@ -68,6 +69,9 @@ bs=blksize Sets the blocksize to blksize. Valid block sizes are 512, quiet The file system will not return an error for disallowed mode changes. +verbose The volume name, file system type and block size will + be written to the syslog. + Handling of the Users/Groups and protection flags ================================================= @@ -104,22 +108,47 @@ The Linux rwxrwxrwx file mode is handled as follows: Newly created files and directories will get the user and group id of the current user and a mode according to the umask. -Linux can read, but not write, Amiga FFS partitions. - -Mount options are - size has the size in 512 byte blocks of the mounted medium. - -Case is significant in filename matching, different to real AFFS. - Command line example +==================== mount Archive/Amiga/Workbench3.1.adf /mnt -t affs -o loop,size=1760 mount /dev/sda3 /Amiga -t affs /etc/fstab example /dev/sdb5 /d/f affs ro -This file system will probably be writeable in future releases. +Bugs, Restrictions, Caveats +=========================== + +Quite a few things may not work as advertised. Not everything is +tested, though several hundred MB have been read and written using +this fs. + +Filenames are truncated to 30 characters without warning. + +Currently there are no checks against invalid characters (':') +in filenames. + +Case is ignored by the affs in filename matching, but Linux shells +do care about the case. Example (with /mnt being an affs mounted fs): + rm /mnt/WRONGCASE +will remove /mnt/wrongcase, but + rm /mnt/WR* +will not since the names are matched by the shell. + +The block allocation is designed for hard disk partitions. If more +than 1 process writes to a (small) diskette, the blocks are allocated +in an ugly way (but the real AFFS doesn't do much better). This +is also true when space gets tight. + +The bitmap valid flag in the root block may not be accurate when the +system crashes while an affs partition is mounted. There's currently +no way to fix this without an Amiga (disk validator) or manually +(who would do this?). Maybe later. + +A fsck.affs and mkfs.affs will probably be available in the future. +Until then, you should do + ln -s /bin/true /etc/fs/mkfs.affs It's not possible to read floppy disks with a normal PC or workstation due to an incompatibility to the Amiga floppy controller. diff --git a/Documentation/isdn/INTERFACE b/Documentation/isdn/INTERFACE index 26e9e3295999..295d1d71e362 100644 --- a/Documentation/isdn/INTERFACE +++ b/Documentation/isdn/INTERFACE @@ -1,3 +1,4 @@ +$Id: INTERFACE,v 1.2 1996/05/18 15:58:53 fritz Exp $ Description of the Interface between Linklevel and Hardwarelevel of isdn4linux: @@ -12,9 +13,29 @@ Description of the Interface between Linklevel and Hardwarelevel the fields. All further communication is done via callbacks using the function-pointers defined in isdn_if. - ATTENTION, CHANGES since version 0.6 are marked with "***CHANGE0.6"! - ATTENTION, CHANGES since version 0.7 are marked with "***CHANGE0.7"! - ATTENTION, CHANGES since version 0.71 are marked with "***CHANGE0.7.1"! + Changes/Version numbering: + + During development of the ISDN subsystem, several changes have been + made to the interface. Before it went into kernel, the package + had a unique version number. The last version, distributed separately + was 0.7.4. When the subsystem went into kernel, every functional unit + got a separate version number. These numbers are shown at initialization, + separated by slashes: + + c.c/t.t/n.n/p.p/a.a + + where + + c.c is the revision of the common code. + t.t is the revision of the tty related code. + n.n is the revision of the network related code. + p.p is the revision of the ppp related code. + a.a is the revision of the audio related code. + + Changes in this document are marked with '***CHANGEx' where x representing + the version number. If that number starts with 0, it refers to the old, + separately distributed package. If it starts with one of the letters + above, it refers to the revision of the corresponding module. 1. Description of the fields of isdn_if: @@ -53,6 +74,11 @@ Description of the Interface between Linklevel and Hardwarelevel void (*rcvcallb)(int, int, u_char*, int); + ***CHANGEc1.14: Declared obsolete. Do NOT use this field/function + anymore, since it will be removed when all current + LL drivers have been changed accordingly. Use + rcvcallb_skb instead. + This field will be set by LL. The HL-driver delivers received data- packets by calling this function. @@ -114,6 +140,11 @@ Description of the Interface between Linklevel and Hardwarelevel int (*writebuf)(int, int, u_char*, int, int); + ***CHANGEc1.14: Declared obsolete. Do NOT use this field/function + anymore, since it will be removed when all current + LL drivers have been changed accordingly. Set this + field to NULL and use writebuf_skb instead. + This field has to be preset by the HL-driver. The given function will be called by the LL for delivering data to be send via B-Channel. @@ -149,11 +180,7 @@ Description of the Interface between Linklevel and Hardwarelevel Length of data accepted on success, else error-code (-EINVAL on oversized packets etc.) -NOTE on writebuf and writebuf_skb: - The HL-driver may initialize one of the fields to NULL, in which case - the LL will call the non-NULL function only. - - int (*writecmd)(u_char*, int, int); + int (*writecmd)(u_char*, int, int, int, int); This field has to be preset by the HL-driver. The given function will be called to perform write-requests on /dev/isdnctrl (i.e. sending commands @@ -169,11 +196,15 @@ NOTE on writebuf and writebuf_skb: memcpy, may NOT use schedule()) 1 = call from user-space. (HL-driver must use memcpy_fromfs, use of schedule() allowed) + int driver-Id. + int channel-number locally to the HL-driver. (starts with 0) + +***CHANGEc1.14: The driver-Id and channel-number are new since this revision. Returnvalue: Length of data accepted on success, else error-code (-EINVAL etc.) - int (*readstat)(u_char*, int, int); + int (*readstat)(u_char*, int, int, int, int); This field has to be preset by the HL-driver. The given function will be called to perform read-requests on /dev/isdnctrl (i.e. reading replies @@ -189,6 +220,10 @@ NOTE on writebuf and writebuf_skb: memcpy, may NOT use schedule()) 1 = call from user-space. (HL-driver must use memcpy_fromfs, use of schedule() allowed) + int driver-Id. + int channel-number locally to the HL-driver. (starts with 0) + +***CHANGEc1.14: The driver-Id and channel-number are new since this revision. Returnvalue: Length of data on success, else error-code (-EINVAL etc.) diff --git a/Documentation/isdn/README b/Documentation/isdn/README index 5d5e339ddb21..a003cd79dc49 100644 --- a/Documentation/isdn/README +++ b/Documentation/isdn/README @@ -119,6 +119,8 @@ README for the ISDN-subsystem AT&X0 BTX-mode off (default) AT&X1 BTX-mode on. (S13.1=1, S14=0, S16=7, S18=7, S19=0) + For voice-mode commands refer to README.audio + 1.3.2 Escape sequence: During a connection, the emulation reacts just like a normal modem to the escape sequence +++. @@ -168,18 +170,34 @@ README for the ISDN-subsystem 1 = Direct tty-send. Bit 1: 0 = T.70 protocol (Only for BTX!) off 1 = T.70 protocol (Only for BTX!) on - 14 0 Layer-2 protocol: (with the ICN-driver - currently always 0) + 14 0 Layer-2 protocol: 0 = X75/LAPB with I-frames 1 = X75/LAPB with UI-frames 2 = X75/LAPB with BUI-frames 3 = HDLC + 4 = Transparent (audio) 15 0 Layer-3 protocol: (at the moment always 0) 0 = transparent 16 250 Send-Packet-size/16 17 8 Window-size for Teles-driver (not yet implemented) - 18 7 Service-Octet-1 + 18 4 Bit coded register, Service-Octet-1 to accept, + or to be used on dialout: + Bit 0: Service 1 (audio) when set. + Bit 1: Service 5 (BTX) when set. + Bit 2: Service 7 (data) when set. + Note: It is possible to set more than one + bit. In this case, on incoming calls + the selected services are accepted, + and if the service is "audio", the + Layer-2-protocol is automatically + changed to 4 regardless of the setting + of register 14. On outgoing calls, + the most significant 1-bit is choosen to + select the outgoing service octet. 19 0 Service-Octet-2 + 20 0 Bit coded register (readonly) + Service-Octet-1 of last call. + Bit mapping is the same like register 18 Last but not least a (at the moment fairly primitive) device to request the line-status (/dev/isdninfo) is made available. @@ -272,9 +290,8 @@ README for the ISDN-subsystem Due to limited hardware-capabilities, there is no way to check the existence of a card. Therefore you need to be sure your card's setup is correct. Also there are bugs in the printed manual of some newer - 16.3 cards. The manual tells the port has to be 0x180. THIS IS WRONG!! - 0xd80 is the correct value! Have a look to the kernel-syslog. With - most of the cards, you should see a line "HSCX version A:5 B:5" there. + 16.3 cards. Have a look to the kernel-syslog. With most of the cards, + you should see a line "HSCX version A:5 B:5" there. 3.1.2 ICN driver. @@ -292,9 +309,10 @@ README for the ISDN-subsystem When using the ICN double card, you MUST define TWO idstrings. idstring must start with a character! - The ICN driver supports only one card at the moment. If you like to - use more than one card, build the modularized version, loading it - more than one time, each module driving a single card. + If you like to use more than one card, you can use the program + "icnctrl" from the utility-package to configure additional cards. + You need to configure shared memory only once, since the icn-driver + maps all cards into the same address-space. Using the "icnctrl"-utility, portbase and shared memory can also be changed during runtime. @@ -335,12 +353,8 @@ README for the ISDN-subsystem When using the ICN double card, you MUST define TWO idstrings. idstring must start with a character! - The ICN driver supports only one card at the moment. If you like to - use more than one card, build the modularized version, loading it - more than one time, each module driving a single card. - - Using the "icnctrl"-utility, portbase and shared memory can also be - changed during runtime. + Using the "icnctrl"-utility, the same features apply to the modularized + version like to the kernel-builtin one. The D-channel protocol is configured by loading different firmware into the card's memory using the "icnctrl"-utility. @@ -365,13 +379,16 @@ README for the ISDN-subsystem For Euro-ISDN: icnctrl [-d IDstring] load download/loadpg.bin download/pc_eu_ca.bin - When using the ICN-2B, the protocol-software for the second half of + When using the ICN-4B, the protocol-software for the second half of the card must be appended to the command line. - -> The two LEDs at the back cover of the card (ICN-2B: 4 LEDs) must be + -> The two LEDs at the back cover of the card (ICN-4B: 4 LEDs) must be blinking intermittently now. If a connection is up, the corresponding led is lit continuously. + For loading pcbit-firmware, refer to Documentation/isdn/README.pcbit + and the pcbit manpage, included in the utility-package. + b) If you only intend to use ttys, you are nearly ready now. c) If you want to have really permanent "Modem"-settings on disk, you diff --git a/Documentation/isdn/README.icn b/Documentation/isdn/README.icn index 66327c35c822..3cd5171ff140 100644 --- a/Documentation/isdn/README.icn +++ b/Documentation/isdn/README.icn @@ -1,3 +1,5 @@ +$Id: README.icn,v 1.3 1996/05/19 00:10:37 fritz Exp $ + You can get the ICN-ISDN-card from: Thinking Objects Software GmbH @@ -16,7 +18,8 @@ The card communicates with the PC by two interfaces: 2. A memory window with 16KB-256KB size, which can be setup in 16k steps over the whole range of 16MB. Isdn4linux only uses a 16k window. The base address of the window can be configured when loading - the lowlevel-module (see README). + the lowlevel-module (see README). If using more than one card, + all cards are mapped to the same window and activated as needed. Setting up the IO-address dipswitches for the ICN-ISDN-card: diff --git a/Documentation/isdn/README.syncppp b/Documentation/isdn/README.syncppp index 5bdc48fdfe6a..27d260095cce 100644 --- a/Documentation/isdn/README.syncppp +++ b/Documentation/isdn/README.syncppp @@ -12,7 +12,7 @@ To compile isdn4linux with the sync PPP part, you have to answer the appropriate question when doing a "make config" Don't forget to load the slhc.o module before the isdn.o module, if VJ-compression support -is not compiled into your kernel. (e.g if you have PPP or +is not compiled into your kernel. (e.g if you have no PPP or CSLIP in the kernel) Using isdn4linux with sync PPP: @@ -20,11 +20,13 @@ Using isdn4linux with sync PPP: Sync PPP is just another encapsulation for isdn4linux. The name to enable sync PPP encapsulation is 'syncppp' .. e.g: - isdn/isdnctrl encap ippp0 syncppp + /sbin/isdnctrl encap ippp0 syncppp The name of the interface is here 'ippp0'. You need one interface with the name 'ippp0' to saturate the ipppd, which checks the ppp version via this interface. +Currently, all devices must have the name ipppX where +'X' is a decimal value. To set up a PPP connection you need the ipppd .. You must start the ipppd once after installing the modules. The ipppd @@ -46,7 +48,8 @@ for an example setup script. To use the MPPP stuff, you must configure a slave device with isdn4linux. Now call the ipppd with the '+mp' option. To increase the number of links, you must use the -'addlink' option of the isdnctrl tool. +'addlink' option of the isdnctrl tool. (rc.isdn.syncppp.MPPP is +an example script) enjoy it, michael diff --git a/Documentation/isdn/syncPPP.FAQ b/Documentation/isdn/syncPPP.FAQ index 5743f6a42253..ab8a1ee217e7 100644 --- a/Documentation/isdn/syncPPP.FAQ +++ b/Documentation/isdn/syncPPP.FAQ @@ -1,32 +1,50 @@ simple isdn4linux PPP FAQ .. to be continued .. not 'debugged' +------------------------------------------------------------------- -Q: pppd,ipppd, syncPPP , asyncPPP .. what is that ? - what should I use? -A: The pppd is for asynchronous PPP .. asynchronous means -here, the framing is character based. (e.g when -using ttyI* or tty* devices) - -The ipppd handles PPP packets coming in HDLC -frames (bit based protocol) ... The PPP driver -in isdn4linux pushes all IP packets direct -to the network layer and all PPP protocol -frames to the /dev/ippp* device. -So, the ipppd is a simple external network -protocol handler. - -If you login into a remote machine using the -/dev/ttyI* devices and then enable PPP on the -remote terminal server -> use the 'old' pppd - -If your remote side immediately starts to send -frames ... you probably connect to a -syncPPP machine .. use the network device part -of isdn4linux with the 'syncppp' encapsulation -and make sure, that the ipppd is running and -connected to at least one /dev/ippp*. Check the -isdn4linux manual on how to configure a network device. - -Q: when I start the ipppd .. I only get the +Q01: what's pppd,ipppd, syncPPP , asyncPPP ?? +Q02: error message "this systems lacks PPP support" +Q03: strange information using 'ifconfig' +Q04: MPPP?? What's that and how can I use it ... +Q05: I tried MPPP but it doesn't work +Q06: can I use asynchronous PPP encapuslation with network devices +Q07: A SunISDN machine can't connect to my i4l system +Q08: I wanna talk to several machines, which need different configs +Q09: Starting the ipppd, I get only error messages from i4l +Q10: I wanna use dynamic IP address assignment +Q11: I can't connect. How can I check where the problem is. +Q12: How can I reduce login delay? + +------------------------------------------------------------------- + +Q01: pppd,ipppd, syncPPP , asyncPPP .. what is that ? + what should I use? +A: The pppd is for asynchronous PPP .. asynchron means + here, the framing is character based. (e.g when + using ttyI* or tty* devices) + + The ipppd handles PPP packets coming in HDLC + frames (bit based protocol) ... The PPP driver + in isdn4linux pushes all IP packets direct + to the network layer and all PPP protocol + frames to the /dev/ippp* device. + So, the ipppd is a simple externel network + protocol handler. + + If you login into a remote machine using the + /dev/ttyI* devices and then enable PPP on the + remote terminal server -> use the 'old' pppd + + If your remote side immediately starts to send + frames ... you probably connect to a + syncPPP machine .. use the network device part + of isdn4linux with the 'syncppp' encapsulation + and make sure, that the ipppd is running and + conneted to at least one /dev/ippp*. Check the + isdn4linux manual on how to configure a network device. + +-- + +Q02: when I start the ipppd .. I only get the error message "this systems lacks PPP support" A: check that at least the device 'ippp0' exists. (you can check this e.g with the program 'ifconfig') @@ -39,12 +57,168 @@ A: Maybe you have compiled the ipppd with another kernel source tree than the kernel you currently run ... -Q: when I list the netdevices with ifconfig I see, that +-- + +Q03: when I list the netdevices with ifconfig I see, that my ISDN interface has a HWaddr and IRQ=0 and Base address = 0 -A: The device is a fake ethernet device .. ignore IRQ and baseaddr +A: The device is a fake ethernetdevice .. ignore IRQ and baseaddr You need the HWaddr only for ethernet encapsulation. +-- + +Q04: MPPP?? What's that and how can I use it ... + +A: MPPP or MP or MPP (Warning: MP is also an + acronym for 'Multi Processor') stands for + Multi Point to Point and means bundling + of several channels to one logical stream. + To enable MPPP negotiation you must call the + ipppd with the '+mp' option. + You must also configure a slave device for + every additional channel. (see the i4l manual + for more) + To use channel bundling you must first activate + the 'master' or inital call. Now you can add + the slave channels with the command: + isdnctrl addlink + e.g: + isdnctrl addlink ippp0 + This is different to other encapsualtions of + isdn4linux! With syncPPP, there is no automatic + activation of slave devices. + +-- + +Q05: I tried MPPP but it doesn't work .. the ipppd + writes in the debug log something like: + .. rcvd [0][proto=0x3d] c0 00 00 00 80 fd 01 01 00 0a ... + .. sent [0][LCP ProtRej id=0x2 00 3d c0 00 00 00 80 fd 01 ... + +A: you forgot to compile MPPP/RFC1717 support into the + ISDN Subsystem. Recompile with this option enabled. + +-- + +Q06: can I use asynchronous PPP encapuslation + over the network interface of isdn4linux .. + +A: No .. that's not possible .. Use the standard + PPP package over the /dev/ttyI* devices. You + must not use the ipppd for this. + +-- + +Q07: A SunISDN machine tries to connect my i4l system, + which doesn't work. + Checking the debug log I just saw garbage like: +!![ ... fill in the line ... ]!! + +A: The Sun tries to talk asynchronous PPP ... i4l + can't understand this ... try to use the ttyI* + devices with the standard PPP/pppd package + +A: (from Alexanter Strauss: ) +!![ ... fill in mail ]!! + +-- + +Q08: A wanna talk to remote machines, which need + a different configuration. The only way + I found to do this is to kill the ipppd and + start a new one with another config to connect + to the second machine. + +A: you must bind a network interface explicitly to + an ippp device, where you can connect a (for this + interface) individualy configured ipppd. + +-- + +Q09: When I start the ipppd I only get error messages + from the i4l driver .. + +A: When starting, the ipppd calls functions which may + trigger a network packet. (e.g gethostbyname()). + Without the ipppd (at this moment, it is not + fully started) we can't handle this network request. + Try to configure hostnames necessary for the ipppd + in your local /etc/hosts file or in a way, that + your system can resolve it without using an + isdn/ippp network-interface. + +-- + +Q10: I wanna use dynamic IP address assignment ... How + must I configure the network device. + +A: At least you must have a routing, which forwards + a packet to the ippp network-interface to trigger + the dial-on-demand. + A default routing to the ippp-interface will work. + Now you must choose a dummy IP address for your + interface. + If for some reason you can't set the default + routing to the ippp interface, you may take any + address of the subnet from which you expect your + dynamic IP number and set a 'network route' for + this subnet to the ippp interface. + To allow overriding of the dummy address you + must call the ipppd with the 'ipcp-accept-local' option. + +A: You must know, how the ipppd gets the addresses it wanna + configure. If you don't give any option, the ipppd + tries to negotiate the local host address! + With the option 'noipdefault' it requests an address + from the remote machine. With 'useifip' it gets the + addresses from the net interface. Or you set the addresse + on the option line with the option. + Note: the IP address of the remote machine must be configured + locally or the remote machine must send it in an IPCP request. + If your side doesn't know the IP address after negotiation, it + closes the connection! + You must allow overriding of address with the 'ipcp-accept-*' + options, if you have set your own or the remote address + explicitly. + +A: Maybe you try these options .. e.g: + + /sbin/ipppd :$REMOTE noipdefault /dev/ippp0 + + where REMOTE must be the address of the remote machine (the + machine, which gives you your address) + +-- + +Q11: I can't connect. How can I check where the problem is. + +A: A good help log is the debug output from the ipppd... + Check whether you can find there: + - only a few LCP-conf-req SENT messages (less then 10) + and then a Term-REQ: + -> check whether your ISDN card is well configured + it seems, that your machine doesn't dial + (IRQ,IO,Proto, etc problems) + Configure your ISDN card to print debug messages and + check the /dev/isdnctrl output next time. There + you can see, whether there is activity on the card/line. + - there are at least a few RECV messages in the log: + -> fine: your card is dialing and your remote machine + tries to talk with you. Maybe only a missing + authentification. Check your ipppd configuration again. + - the ipppd exits for some reason: + -> not good ... check /var/adm/syslog and /var/adm/daemon. + Could be a bug in the ipppd. + +-- + +Q12: How can I reduce login delay? + +A: Log a login session ('debug' log) and check which options + your remote side rejects. Next time configure your ipppd + to not negotiate these options. Another 'side effect' is, that + this increases redundancy. (e.g your remote side is buggy and + rejects options in a wrong way). diff --git a/Makefile b/Makefile index 1e0937b7af19..cf960dc84f6f 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 99 -SUBLEVEL = 5 +SUBLEVEL = 6 ARCH = i386 diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig index 174ecb0349d6..ae3db1ea8ee8 100644 --- a/arch/alpha/defconfig +++ b/arch/alpha/defconfig @@ -24,6 +24,7 @@ CONFIG_NATIVE=y # CONFIG_ALPHA_EB66P is not set # CONFIG_ALPHA_EB64P is not set CONFIG_ALPHA_EB164=y +# CONFIG_ALPHA_PC164 is not set # CONFIG_ALPHA_JENSEN is not set # CONFIG_ALPHA_NONAME is not set # CONFIG_ALPHA_P2K is not set @@ -47,11 +48,15 @@ CONFIG_BLK_DEV_FD=y # Please see drivers/block/README.ide for help/info on IDE drives # # CONFIG_BLK_DEV_HD_ONLY is not set + +# +# Additional Block Devices +# +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y # CONFIG_BLK_DEV_INITRD is not set -# CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_XD is not set -# CONFIG_BLK_DEV_MD is not set # # Networking options @@ -120,7 +125,7 @@ CONFIG_SCSI_NCR53C7xx_FAST=y # CONFIG_SCSI_NCR53C7xx_DISCONNECT is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_QLOGIC is not set +# CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_ULTRASTOR is not set diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index fd4575af7a0e..24145c4af0af 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -70,9 +70,9 @@ asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask, force_sig(SIGFPE, current); } -asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs regs) +asmlinkage void do_entIF(unsigned long type, unsigned long a1, + unsigned long a2, unsigned long a3, unsigned long a4, + unsigned long a5, struct pt_regs regs) { extern int ptrace_cancel_bpt (struct task_struct *who); @@ -201,18 +201,18 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg, if (reg >= 16 && reg <= 18) reg += 19; switch (opcode) { - case 0x28: /* ldl */ - *(reg+regs.regs) = (int) ldl_u(va); - return; - case 0x29: /* ldq */ - *(reg+regs.regs) = ldq_u(va); - return; - case 0x2c: /* stl */ - stl_u(*(reg+regs.regs), va); - return; - case 0x2d: /* stq */ - stq_u(*(reg+regs.regs), va); - return; + case 0x28: /* ldl */ + *(reg+regs.regs) = get_unaligned((int *)va); + return; + case 0x29: /* ldq */ + *(reg+regs.regs) = get_unaligned((long *)va); + return; + case 0x2c: /* stl */ + put_unaligned(*(reg+regs.regs), (int *)va); + return; + case 0x2d: /* stq */ + put_unaligned(*(reg+regs.regs), (long *)va); + return; } printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n", regs.pc, va, opcode, reg); @@ -321,45 +321,79 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg reg_addr = frame; if (opcode >= 0x28) { /* it's an integer load/store */ - if (reg < 9) { - reg_addr += 7 + reg; /* v0-t7 in SAVE_ALL frame */ - } else if (reg < 16) { - reg_addr += (reg - 9); /* s0-s6 in entUna frame */ - } else if (reg < 19) { - reg_addr += 7 + 20 + 3 + (reg - 16); /* a0-a2 in PAL frame */ - } else if (reg < 29) { - reg_addr += 7 + 9 + (reg - 19); /* a3-at in SAVE_ALL frame */ - } else { - switch (reg) { - case 29: /* gp in PAL frame */ - reg_addr += 7 + 20 + 2; - break; - case 30: /* usp in PAL regs */ - usp = rdusp(); - reg_addr = &usp; - break; - case 31: /* zero "register" */ - reg_addr = &zero; - break; - } + switch (reg) { + case 0: case 1: case 2: case 3: case 4: + case 5: case 6: case 7: case 8: + /* v0-t7 in SAVE_ALL frame */ + reg_addr += 7 + reg; + break; + + case 9: case 10: case 11: case 12: + case 13: case 14: case 15: + /* s0-s6 in entUna frame */ + reg_addr += (reg - 9); + break; + + case 16: case 17: case 18: + /* a0-a2 in PAL frame */ + reg_addr += 7 + 20 + 3 + (reg - 16); + break; + + case 19: case 20: case 21: case 22: case 23: + case 24: case 25: case 26: case 27: case 28: + /* a3-at in SAVE_ALL frame */ + reg_addr += 7 + 9 + (reg - 19); + break; + + case 29: + /* gp in PAL frame */ + reg_addr += 7 + 20 + 2; + break; + + case 30: + /* usp in PAL regs */ + usp = rdusp(); + reg_addr = &usp; + break; + + case 31: + /* zero "register" */ + reg_addr = &zero; + break; } } switch (opcode) { - case 0x22: /* lds */ - alpha_write_fp_reg(reg, s_mem_to_reg(ldl_u(va))); + case 0x22: /* lds */ + alpha_write_fp_reg(reg, s_mem_to_reg( + get_unaligned((unsigned int *)va))); break; - case 0x26: /* lds */ - alpha_write_fp_reg(reg, s_reg_to_mem(ldl_u(va))); + case 0x26: /* sts */ + put_unaligned(s_reg_to_mem(alpha_read_fp_reg(reg)), + (unsigned int *)va); break; - case 0x23: alpha_write_fp_reg(reg, ldq_u(va)); break; /* ldt */ - case 0x27: stq_u(alpha_read_fp_reg(reg), va); break; /* stt */ + case 0x23: /* ldt */ + alpha_write_fp_reg(reg, get_unaligned((unsigned long *)va)); + break; + case 0x27: /* stt */ + put_unaligned(alpha_read_fp_reg(reg), (unsigned long *)va); + break; + + case 0x28: /* ldl */ + *reg_addr = get_unaligned((int *)va); + break; + case 0x2c: /* stl */ + put_unaligned(*reg_addr, (int *)va); + break; + + case 0x29: /* ldq */ + *reg_addr = get_unaligned((long *)va); + break; + case 0x2d: /* stq */ + put_unaligned(*reg_addr, (long *)va); + break; - case 0x28: *reg_addr = (int) ldl_u(va); break; /* ldl */ - case 0x29: *reg_addr = ldq_u(va); break; /* ldq */ - case 0x2c: stl_u(*reg_addr, va); break; /* stl */ - case 0x2d: stq_u(*reg_addr, va); break; /* stq */ default: *pc_addr -= 4; /* make pc point to faulting insn */ force_sig(SIGBUS, current); @@ -383,10 +417,11 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg * got terminally tainted by VMS at some point. */ asmlinkage long do_entSys(unsigned long a0, unsigned long a1, unsigned long a2, - unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs) + unsigned long a3, unsigned long a4, unsigned long a5, + struct pt_regs regs) { if (regs.r0 != 112) - printk("", regs.r0, a0, a1, a2); + printk("", regs.r0, a0, a1, a2); return -1; } diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S index 3db2f7c9517a..994b5c195470 100644 --- a/arch/i386/boot/video.S +++ b/arch/i386/boot/video.S @@ -880,7 +880,7 @@ vesa1: seg gs ! Get next mode in the list cmp ax,#0x0080 ! Check validity of mode ID jc vesa2 or ah,ah ! Valid ID's are 0x0000-0x007f and 0x0100-0x07ff - jz vesan ! [Certain BIOSes errorneously report 0x80-0xff] + jz vesan ! [Certain BIOSes erroneously report 0x80-0xff] cmp ax,#0x0800 jnc vesae vesa2: push cx diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 252db60ca1e1..f0526b083188 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -44,13 +44,17 @@ CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDE_PCMCIA is not set CONFIG_BLK_DEV_CMD640=y -CONFIG_BLK_DEV_RZ1000=y # CONFIG_BLK_DEV_TRITON is not set +CONFIG_BLK_DEV_RZ1000=y # CONFIG_IDE_CHIPSETS is not set -# CONFIG_BLK_DEV_RAM is not set + +# +# Additional Block Devices +# # CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_XD is not set # CONFIG_BLK_DEV_MD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_XD is not set # # Networking options diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S index 4a55b1624196..795d7466e8ac 100644 --- a/arch/m68k/kernel/head.S +++ b/arch/m68k/kernel/head.S @@ -375,7 +375,7 @@ ENTRY(_start) movel %d1,%a2@+ /* * %a2 points now to the page table entry for available pages at %a6, - * hence caching modes for new pages can easiely set unless increasing + * hence caching modes for new pages can easily set unless increasing * of %a2 are forgotten. */ Lnot040: diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 7a86984ec2e9..d663335f1660 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -30,21 +30,16 @@ #include -#ifdef __alpha__ /* - * On the Alpha, we get unaligned access exceptions on - * p->nr_sects and p->start_sect, when the partition table - * is not on a 4-byte boundary, which is frequently the case. - * This code uses unaligned load instructions to prevent - * such exceptions. + * Many architectures don't like unaligned accesses, which is + * frequently the case with the nr_sects and start_sect partition + * table entries. */ #include -#define NR_SECTS(p) ldl_u(&p->nr_sects) -#define START_SECT(p) ldl_u(&p->start_sect) -#else /* __alpha__ */ -#define NR_SECTS(p) p->nr_sects -#define START_SECT(p) p->start_sect -#endif /* __alpha__ */ + +#define NR_SECTS(p) get_unaligned(&p->nr_sects) +#define START_SECT(p) get_unaligned(&p->start_sect) + struct gendisk *gendisk_head = NULL; diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index 50b7a7fd71e5..9088f75eee6f 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -97,6 +97,7 @@ * 3.12 May 7, 1996 -- Rudimentary changer support. Based on patches * from Gerhard Zuber . * Let open succeed even if there's no loaded disc. + * 3.13 May 19, 1996 -- Fixes for changer code. * * NOTE: Direct audio reads will only work on some types of drive. * So far, i've received reports of success for Sony and Toshiba drives. @@ -106,6 +107,7 @@ * uses a different protocol. * * ATAPI cd-rom driver. To be used with ide.c. + * See Documentation/cdrom/ide-cd for usage information. * * Copyright (C) 1994, 1995, 1996 scott snyder * May be copied or modified under the terms of the GNU General Public License @@ -130,9 +132,7 @@ #include #include #include -#ifdef __alpha__ -# include -#endif +#include #include "ide.h" @@ -1149,11 +1149,7 @@ static void cdrom_start_read_continuation (ide_drive_t *drive) pc.c[0] = READ_10; pc.c[7] = (nframes >> 8); pc.c[8] = (nframes & 0xff); -#ifdef __alpha__ - stl_u (htonl (frame), (unsigned int *) &pc.c[2]); -#else - *(int *)(&pc.c[2]) = htonl (frame); -#endif + put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]); /* Send the command to the drive and return. */ (void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), @@ -1937,11 +1933,7 @@ cdrom_read_block (ide_drive_t *drive, int format, int lba, pc.c[0] = READ_CD; pc.c[1] = (format << 2); -#ifdef __alpha__ - stl_u(htonl (lba), (unsigned int *) &pc.c[2]); -#else - *(int *)(&pc.c[2]) = htonl (lba); -#endif + put_unaligned(htonl(lba), (unsigned int *) &pc.c[2]); pc.c[8] = 1; /* one block */ pc.c[9] = 0x10; @@ -1968,7 +1960,7 @@ cdrom_read_block (ide_drive_t *drive, int format, int lba, /* If SLOT<0, unload the current slot. Otherwise, try to load SLOT. */ static int -cdrom_load_unload (ide_drive_t *drive, unsigned long slot, +cdrom_load_unload (ide_drive_t *drive, int slot, struct atapi_request_sense *reqbuf) { struct packet_command pc; @@ -2403,16 +2395,14 @@ int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode, if (drive->usage > 1) return -EBUSY; - stat = cdrom_load_unload (drive, -1, NULL); - if (stat) return stat; + (void) cdrom_load_unload (drive, -1, NULL); cdrom_saw_media_change (drive); if (arg == -1) { (void) cdrom_lockdoor (drive, 0, NULL); return 0; } - stat = cdrom_load_unload (drive, arg, NULL); - if (stat) return stat; + (void) cdrom_load_unload (drive, (int)arg, NULL); stat = cdrom_check_status (drive, &my_reqbuf); if (stat && my_reqbuf.sense_key == NOT_READY) { @@ -2642,7 +2632,6 @@ void ide_cdrom_setup (ide_drive_t *drive) * Establish interfaces for an IDE port driver, and break out the cdrom * code into a loadable module. * Support changers better. - * Write some real documentation. */ diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 11410f4ca7d7..6933b8153391 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -286,9 +286,17 @@ static void make_request(int major,int rw, struct buffer_head * bh) count = bh->b_size >> 9; sector = bh->b_rsector; + + /* Uhhuh.. Nasty dead-lock possible here.. */ + if (buffer_locked(bh)) + return; + /* Maybe the above fixes it, and maybe it doesn't boot. Life is interesting */ + + lock_buffer(bh); + if (blk_size[major]) if (blk_size[major][MINOR(bh->b_rdev)] < (sector + count)>>1) { - bh->b_state = 0; + bh->b_state &= (1 << BH_Lock) | (1 << BH_FreeOnIO); /* This may well happen - the kernel calls bread() without checking the size of the device, e.g., when mounting a device. */ @@ -298,13 +306,9 @@ static void make_request(int major,int rw, struct buffer_head * bh) kdevname(bh->b_rdev), rw, (sector + count)>>1, blk_size[major][MINOR(bh->b_rdev)]); + unlock_buffer(bh); return; } - /* Uhhuh.. Nasty dead-lock possible here.. */ - if (buffer_locked(bh)) - return; - /* Maybe the above fixes it, and maybe it doesn't boot. Life is interesting */ - lock_buffer(bh); rw_ahead = 0; /* normal case; gets changed below for READA/WRITEA */ switch (rw) { diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c index 18e4f2319aee..637739c1ef0a 100644 --- a/drivers/cdrom/aztcd.c +++ b/drivers/cdrom/aztcd.c @@ -1,5 +1,5 @@ -#define AZT_VERSION "2.40" -/* $Id: aztcd.c,v 2.40 1996/05/01 11:09:35 root Exp root $ +#define AZT_VERSION "2.50" +/* $Id: aztcd.c,v 2.50 1996/05/17 16:19:03 root Exp root $ linux/drivers/block/aztcd.c - Aztech CD268 CDROM driver Copyright (C) 1994,95,96 Werner Zimmermann(zimmerma@rz.fht-esslingen.de) @@ -151,6 +151,9 @@ V2.40 Reorganized the placement of functions in the source code file to reflect the layered approach; did not actually change code Werner Zimmermann, May 1, 96 + V2.50 Heiko Eissfeld suggested to remove some VERIFY_READs in + aztcd_ioctl; check_aztcd_media_change modified + Werner Zimmermann, May 16, 96 */ #include #include @@ -1053,10 +1056,15 @@ void aztcd_setup(char *str, int *ints) } /* - * Checking if the media has been changed not yet implemented + * Checking if the media has been changed */ static int check_aztcd_media_change(kdev_t full_dev) -{ return 0; +{ if (aztDiskChanged) /* disk changed */ + { aztDiskChanged=0; + return 1; + } + else + return 0; /* no change */ } /* @@ -1127,7 +1135,7 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsi #ifdef AZT_DEBUG printk("aztcd ioctl MULTISESSION\n"); #endif - st = verify_area(VERIFY_READ, (void*) arg, sizeof(struct cdrom_multisession)); + st = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct cdrom_multisession)); if (st) return st; memcpy_fromfs(&ms, (void*) arg, sizeof(struct cdrom_multisession)); if (ms.addr_format == CDROM_MSF) @@ -1140,8 +1148,6 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsi else return -EINVAL; ms.xa_flag = DiskInfo.xa; - st = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct cdrom_multisession)); - if (st) return st; memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession)); #ifdef AZT_DEBUG if (ms.addr_format == CDROM_MSF) @@ -1225,8 +1231,6 @@ azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame); memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr); break; case CDROMREADTOCENTRY: /* Read an entry in the table of contents */ - st = verify_area(VERIFY_READ, (void *) arg, sizeof entry); - if (st) return st; st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry); if (st) return st; memcpy_fromfs(&entry, (void *) arg, sizeof entry); @@ -1254,17 +1258,10 @@ azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame); memcpy_tofs((void *) arg, &entry, sizeof entry); break; case CDROMSUBCHNL: /* Get subchannel info */ - st = verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_subchnl)); - if (st) { -#ifdef AZT_DEBUG - printk("aztcd: exiting aztcd_ioctl - Error 1 - Command:%x\n",cmd); -#endif - return st; - } st = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl)); if (st) { #ifdef AZT_DEBUG - printk("aztcd: exiting aztcd_ioctl - Error 2 - Command:%x\n",cmd); + printk("aztcd: exiting aztcd_ioctl - Error 1 - Command:%x\n",cmd); #endif return st; } @@ -1340,9 +1337,7 @@ azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame); #if AZT_PRIVATE_IOCTLS case CDROMREADCOOKED: /*read data in mode 1 (2048 Bytes)*/ case CDROMREADRAW: /*read data in mode 2 (2336 Bytes)*/ - { st = verify_area(VERIFY_READ, (void *) arg, sizeof msf); - if (st) return st; - st = verify_area(VERIFY_WRITE, (void *) arg, sizeof buf); + { st = verify_area(VERIFY_WRITE, (void *) arg, sizeof buf); if (st) return st; memcpy_fromfs(&msf, (void *) arg, sizeof msf); /* convert to bcd */ diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c index f2b2094e949d..4c38cd6f73e2 100644 --- a/drivers/cdrom/mcdx.c +++ b/drivers/cdrom/mcdx.c @@ -27,7 +27,7 @@ * Daniel v. Mosnenck (he sent me the Technical and Programming Reference) * Gerd Knorr (he lent me his PhotoCD) * Nils Faerber and Roger E. Wolff (extensively tested the LU portion) - * Andreas Kies (testing the mysterious hang up's) + * Andreas Kies (testing the mysterious hangups) * ... somebody forgotten? * * 2.1 1996/04/29 Marcin Dalecki @@ -38,8 +38,8 @@ * 2.3 1996/05/15 Marcin Dalecki * Fixed stereo support. * NOTE: - * There will be propably a 3.0 adhering to the new generic non ATAPI - * cdrom interface in the unforseen future. + * There will be probably a 3.0 adhering to the new generic non ATAPI + * cdrom interface in the unforeseen future. */ #define VERSION "2.3" @@ -261,8 +261,8 @@ static inline int irq(int *ip) * Return drives status in case of success, -1 otherwise. * * First we try to get the status information quickly. - * Then we sleep repeatedly for about 10 usecs, befor we finally reach the - * timeout. For this reason this command must be called with the drive beeing + * Then we sleep repeatedly for about 10 usecs, before we finally reach the + * timeout. For this reason this command must be called with the drive being * locked! */ static int get_status(struct s_drive_stuff *stuffp, @@ -462,7 +462,7 @@ int read_toc(struct s_drive_stuff *stuffp) set_drive_mode(stuffp, DATA); return -EIO; } - /* now read actually the index tarcks */ + /* now read actually the index tracks */ for (trk = 0; trk < (stuffp->n_last - stuffp->n_first + 1); trk++) @@ -563,8 +563,8 @@ static int mcdx_ioctl(struct inode *ip, struct file *fp, /* * Update disk information, when necessary. * This part will only work, when the new disk is of the same type as - * the one which was previousley there, esp. also for audio diks. - * This doesn't hurt us, since otherwise the mouting/unmounting scheme + * the one which was previously there, esp. also for audio disks. + * This doesn't hurt us, since otherwise the mounting/unmounting scheme * will ensure correct operation. */ if (stuffp->xxx) { /* disk changed */ @@ -797,7 +797,7 @@ static int mcdx_ioctl(struct inode *ip, struct file *fp, return ans; memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl)); - /* Adjust for the wiredness of workman. */ + /* Adjust for the weirdness of workman. */ volctrl.channel2 = volctrl.channel1; volctrl.channel1 = volctrl.channel3 = 0x00; return talk(stuffp, MCDX_CMD_SET_ATTENATOR, @@ -815,7 +815,7 @@ static int mcdx_ioctl(struct inode *ip, struct file *fp, * This does actually the transfer from the drive. * Return: -1 on timeout or other error * else status byte (as in stuff->st) - * FIXME: the excessive jumping throught wait queues degrades the + * FIXME: the excessive jumping through wait queues degrades the * performance significantly. */ static int transfer_data(struct s_drive_stuff *stuffp, @@ -1179,7 +1179,7 @@ static int mcdx_media_change(kdev_t full_dev) MCDX_TRACE(("mcdx_media_change()\n")); /* - * FIXME: propably this is unneded or should be simplified! + * FIXME: probably this is unneeded or should be simplified! */ issue_command(stuffp = mcdx_stuffp[MINOR(full_dev)], MCDX_CMD_GET_STATUS, 5 * HZ); @@ -1197,7 +1197,7 @@ static void mcdx_intr(int irq, void *dev_id, struct pt_regs *regs) u_char b; if (!(stuffp = mcdx_irq_map[irq])) { - return; /* hugh? */ + return; /* huh? */ } /* NOTE: We only should get interrupts if data were requested. @@ -1225,7 +1225,7 @@ static void mcdx_intr(int irq, void *dev_id, struct pt_regs *regs) /* * FIXME! - * This seems to hang badly, when the driver is loaded with inappriopriate + * This seems to hang badly, when the driver is loaded with inappropriate * port/irq settings! */ int mcdx_init(void) diff --git a/drivers/char/README.baycom b/drivers/char/README.baycom index 469b337d45f4..25f2f5846ed0 100644 --- a/drivers/char/README.baycom +++ b/drivers/char/README.baycom @@ -79,7 +79,7 @@ or leave this task to kerneld (if installed). Add the following line to Configuring the driver -Everytime the driver is inserted into the kernel, it has to know which +Every time the driver is inserted into the kernel, it has to know which modems it should access at which ports. This can be done with the setbaycom utility. If you are only using one modem, you can also configure the driver from the insmod command line (or by means of an option line in diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c index 5666b2a406f9..be1490a8bc32 100644 --- a/drivers/char/pcxx.c +++ b/drivers/char/pcxx.c @@ -1868,6 +1868,9 @@ static int pcxe_ioctl(struct tty_struct *tty, struct file * file, return 0; case TIOCSSOFTCAR: + error = verify_area(VERIFY_READ, (void *) arg,sizeof(long)); + if(error) + return error; arg = get_fs_long((unsigned long *) arg); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; @@ -1905,6 +1908,9 @@ static int pcxe_ioctl(struct tty_struct *tty, struct file * file, case TIOCMBIC: case TIOCMODS: case TIOCMSET: + error = verify_area(VERIFY_READ, (void *) arg,sizeof(long)); + if(error) + return error; mstat = get_fs_long((unsigned long *) arg); mflag = 0; diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in index 5fd9edb62814..96f7e5a43b8e 100644 --- a/drivers/isdn/Config.in +++ b/drivers/isdn/Config.in @@ -8,6 +8,7 @@ if [ "$CONFIG_INET" != "n" ]; then bool 'Support generic MP (RFC 1717)' CONFIG_ISDN_MPP fi fi -dep_tristate 'ICN B1 and B2 support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN +bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO +dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN dep_tristate 'Teles/NICCY1016PC/Creatix support' CONFIG_ISDN_DRV_TELES $CONFIG_ISDN diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile index 65f670558ffb..3b441835e722 100644 --- a/drivers/isdn/Makefile +++ b/drivers/isdn/Makefile @@ -18,6 +18,9 @@ ifeq ($(CONFIG_ISDN),y) ifdef CONFIG_ISDN_PPP L_OBJS += isdn_ppp.o endif + ifdef CONFIG_ISDN_AUDIO + L_OBJS += isdn_audio.o + endif else ifeq ($(CONFIG_ISDN),m) M_OBJS += isdn.o @@ -27,6 +30,9 @@ else ifdef CONFIG_ISDN_PPP O_OBJS += isdn_ppp.o endif + ifdef CONFIG_ISDN_AUDIO + O_OBJS += isdn_audio.o + endif endif endif diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index 9c8e068d8139..6f5d4c8bbad2 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -1,4 +1,4 @@ -/* $Id icn.c,v 1.15 1996/01/10 20:57:39 fritz Exp fritz $ +/* $Id: icn.c,v 1.22 1996/05/17 15:46:41 fritz Exp $ * * ISDN low-level module for the ICN active ISDN-Card. * @@ -19,6 +19,22 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.c,v $ + * Revision 1.22 1996/05/17 15:46:41 fritz + * Removed own queue management. + * Changed queue management to use sk_buffs. + * + * Revision 1.21 1996/05/02 04:01:20 fritz + * Bugfix: + * - icn_addcard() evalueated wrong driverId. + * + * Revision 1.20 1996/05/02 00:40:27 fritz + * Major rewrite to support more than one card + * with a single module. + * Support for new firmware. + * + * Revision 1.19 1996/04/21 17:43:32 fritz + * Changes for Support of new Firmware BRV3.02 + * * Revision 1.18 1996/04/20 16:50:26 fritz * Fixed status-buffer overrun. * Misc. typos @@ -86,8 +102,6 @@ #include "icn.h" - - /* * Verbose bootcode- and protocol-downloading. */ @@ -98,58 +112,29 @@ */ #undef MAP_DEBUG -/* If defined, no bootcode- and protocol-downloading is supported and - * you must use an external loader - */ -#undef LOADEXTERN - static char -*revision = "$Revision: 1.18 $"; - -static void icn_pollcard(unsigned long dummy); +*revision = "$Revision: 1.22 $"; -/* Try to allocate a new buffer, link it into queue. */ -static u_char * - icn_new_buf(pqueue ** queue, int length) -{ - pqueue *p; - pqueue *q; - - if ((p = *queue)) { - while (p) { - q = p; - p = (pqueue *) p->next; - } - p = (pqueue *) kmalloc(sizeof(pqueue) + length, GFP_ATOMIC); - q->next = (u_char *) p; - } else - p = *queue = (pqueue *) kmalloc(sizeof(pqueue) + length, GFP_ATOMIC); - if (p) { - p->size = sizeof(pqueue) + length; - p->length = length; - p->next = NULL; - p->rptr = p->buffer; - return p->buffer; - } else { - return (u_char *) NULL; - } -} +static int icn_addcard(int, char *, char *); -#ifdef MODULE -static void icn_free_queue(pqueue ** queue) +/* + * Free queue completely. + * Parameter: + * queue = pointer to queue-head + */ +static void icn_free_queue(struct sk_buff_head *queue) { - pqueue *p; - pqueue *q; - - p = *queue; - while (p) { - q = p; - p = (pqueue *) p->next; - kfree_s(q, q->size); - } - *queue = (pqueue *) 0; + struct sk_buff *skb; + unsigned long flags; + + save_flags(flags); + cli(); + while ((skb = skb_dequeue(queue))) { + skb->free = 1; + kfree_skb(skb, FREE_WRITE); + } + restore_flags(flags); } -#endif /* Put a value into a shift-register, highest bit first. * Parameters: @@ -159,241 +144,257 @@ static void icn_free_queue(pqueue ** queue) * bitcount = Number of bits to output */ static inline void icn_shiftout(unsigned short port, - unsigned long val, - int firstbit, - int bitcount) + unsigned long val, + int firstbit, + int bitcount) { - register u_char s; - register u_char c; + register u_char s; + register u_char c; - for (s = firstbit, c = bitcount; c > 0; s--, c--) - OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port); + for (s = firstbit, c = bitcount; c > 0; s--, c--) + OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port); } /* - * Map Cannel0 (Bank0/Bank8) or Channel1 (Bank4/Bank12) + * disable a cards shared memory */ -static inline void icn_map_channel(int channel) +static inline void icn_disable_ram(icn_card *card) { - static u_char chan2bank[] = - {0, 4, 8, 12}; + OUTB_P(0, ICN_MAPRAM); +} +/* + * enable a cards shared memory + */ +static inline void icn_enable_ram(icn_card *card) +{ + OUTB_P(0xff, ICN_MAPRAM); +} + +/* + * Map a cards channel0 (Bank0/Bank8) or channel1 (Bank4/Bank12) + */ +static inline void icn_map_channel(icn_card *card, int channel) +{ #ifdef MAP_DEBUG - printk(KERN_DEBUG "icn_map_channel %d %d\n", dev->channel, channel); + printk(KERN_DEBUG "icn_map_channel %d %d\n", dev->channel, channel); #endif - if (channel == dev->channel) - return; - OUTB_P(0, ICN_MAPRAM); /* Disable RAM */ - icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4); /* Select Bank */ - OUTB_P(0xff, ICN_MAPRAM); /* Enable RAM */ - dev->channel = channel; + if ((channel == dev.channel) && (card == dev.mcard)) + return; + if (dev.mcard) + icn_disable_ram(dev.mcard); + icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4); /* Select Bank */ + icn_enable_ram(card); + dev.mcard = card; + dev.channel = channel; #ifdef MAP_DEBUG - printk(KERN_DEBUG "icn_map_channel done\n"); + printk(KERN_DEBUG "icn_map_channel done\n"); #endif } -static inline int icn_lock_channel(int channel) +/* + * Lock a cards channel. + * Return 0 if requested card/channel is unmapped (failure). + * Return 1 on success. + */ +static inline int icn_lock_channel(icn_card *card, int channel) { - register int retval; - ulong flags; + register int retval; + ulong flags; #ifdef MAP_DEBUG - printk(KERN_DEBUG "icn_lock_channel %d\n", channel); + printk(KERN_DEBUG "icn_lock_channel %d\n", channel); #endif - save_flags(flags); - cli(); - if (dev->channel == channel) { - dev->chanlock++; - retval = 1; + save_flags(flags); + cli(); + if ((dev.channel == channel) && (card == dev.mcard)) { + dev.chanlock++; + retval = 1; #ifdef MAP_DEBUG - printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel); + printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel); #endif - } else { - retval = 0; + } else { + retval = 0; #ifdef MAP_DEBUG - printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, dev->channel); + printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, device->channel); #endif - } - restore_flags(flags); - return retval; + } + restore_flags(flags); + return retval; } +/* + * Release current card/channel lock + */ static inline void icn_release_channel(void) { - ulong flags; + ulong flags; #ifdef MAP_DEBUG - printk(KERN_DEBUG "icn_release_channel l=%d\n", dev->chanlock); + printk(KERN_DEBUG "icn_release_channel l=%d\n", device->chanlock); #endif - save_flags(flags); - cli(); - if (dev->chanlock) - dev->chanlock--; - restore_flags(flags); + save_flags(flags); + cli(); + if (dev.chanlock) + dev.chanlock--; + restore_flags(flags); } -static inline int icn_trymaplock_channel(int channel) +/* + * Try to map and lock a cards channel. + * Return 1 on success, 0 on failure. + */ +static inline int icn_trymaplock_channel(icn_card *card, int channel) { - ulong flags; + ulong flags; - save_flags(flags); - cli(); + save_flags(flags); + cli(); #ifdef MAP_DEBUG - printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev->channel, - dev->chanlock); + printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel, + dev.chanlock); #endif - if ((!dev->chanlock) || (dev->channel == channel)) { - dev->chanlock++; - icn_map_channel(channel); - restore_flags(flags); + if ((!dev.chanlock) || + ((dev.channel == channel) && (dev.mcard == card))) { + dev.chanlock++; + icn_map_channel(card,channel); + restore_flags(flags); #ifdef MAP_DEBUG - printk(KERN_DEBUG "trymaplock %d OK\n", channel); + printk(KERN_DEBUG "trymaplock %d OK\n", channel); #endif - return 1; - } - restore_flags(flags); + return 1; + } + restore_flags(flags); #ifdef MAP_DEBUG - printk(KERN_DEBUG "trymaplock %d FAILED\n", channel); + printk(KERN_DEBUG "trymaplock %d FAILED\n", channel); #endif - return 0; + return 0; } -static inline void icn_maprelease_channel(int channel) +/* + * Release currend card/channel lock, + * then map same or other channel without locking. + */ +static inline void icn_maprelease_channel(icn_card *card, int channel) { - ulong flags; + ulong flags; - save_flags(flags); - cli(); + save_flags(flags); + cli(); #ifdef MAP_DEBUG - printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev->chanlock); + printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock); #endif - if (dev->chanlock) - dev->chanlock--; - if (!dev->chanlock) - icn_map_channel(channel); - restore_flags(flags); + if (dev.chanlock) + dev.chanlock--; + if (!dev.chanlock) + icn_map_channel(card,channel); + restore_flags(flags); } /* Get Data from the B-Channel, assemble fragmented packets and put them * into receive-queue. Wake up any B-Channel-reading processes. - * This routine is called via timer-callback from pollbchan(). - * It schedules itself while any B-Channel is open. + * This routine is called via timer-callback from icn_pollbchan(). */ -#ifdef DEBUG_RCVCALLBACK -static int max_pending[2] = -{0, 0}; -#endif - -static void icn_pollbchan_receive(int channel, icn_dev * dev) +static void icn_pollbchan_receive(int channel, icn_card *card) { - int mch = channel + ((dev->secondhalf) ? 2 : 0); - int eflag; - int cnt; - int flags; -#ifdef DEBUG_RCVCALLBACK - int rcv_pending1; - int rcv_pending2; - int akt_pending; -#endif - - if (icn_trymaplock_channel(mch)) { - while (rbavl) { - cnt = rbuf_l; - if ((dev->rcvidx[channel] + cnt) > 4000) { - printk(KERN_WARNING "icn: bogus packet on ch%d, dropping.\n", - channel + 1); - dev->rcvidx[channel] = 0; - eflag = 0; - } else { - memcpy(&dev->rcvbuf[channel][dev->rcvidx[channel]], rbuf_d, cnt); - dev->rcvidx[channel] += cnt; - eflag = rbuf_f; - } - rbnext; - icn_maprelease_channel(mch & 2); - if (!eflag) { - save_flags(flags); - cli(); -#ifdef DEBUG_RCVCALLBACK - rcv_pending1 = - (dev->shmem->data_control.ecnr > dev->shmem->data_control.ecns) ? - 0xf - dev->shmem->data_control.ecnr + dev->shmem->data_control.ecns : - dev->shmem->data_control.ecns - dev->shmem->data_control.ecnr; -#endif - dev->interface.rcvcallb(dev->myid, channel, dev->rcvbuf[channel], - dev->rcvidx[channel]); - dev->rcvidx[channel] = 0; -#ifdef DEBUG_RCVCALLBACK - rcv_pending2 = - (dev->shmem->data_control.ecnr > dev->shmem->data_control.ecns) ? - 0xf - dev->shmem->data_control.ecnr + dev->shmem->data_control.ecns : - dev->shmem->data_control.ecns - dev->shmem->data_control.ecnr; - akt_pending = rcv_pending2 - rcv_pending1; - if (akt_pending > max_pending[channel]) { - max_pending[channel] = akt_pending; - printk(KERN_DEBUG "ICN_DEBUG: pend: %d %d\n", max_pending[0], max_pending[1]); - } -#endif - restore_flags(flags); - } - if (!icn_trymaplock_channel(mch)) - break; - } - icn_maprelease_channel(mch & 2); - } + int mch = channel + ((card->secondhalf) ? 2 : 0); + int eflag; + int cnt; + struct sk_buff *skb; + + if (icn_trymaplock_channel(card,mch)) { + while (rbavl) { + cnt = rbuf_l; + if ((card->rcvidx[channel] + cnt) > 4000) { + printk(KERN_WARNING + "icn: (%s) bogus packet on ch%d, dropping.\n", + CID, + channel + 1); + card->rcvidx[channel] = 0; + eflag = 0; + } else { + memcpy(&card->rcvbuf[channel][card->rcvidx[channel]], rbuf_d, cnt); + card->rcvidx[channel] += cnt; + eflag = rbuf_f; + } + rbnext; + icn_maprelease_channel(card, mch & 2); + if (!eflag) { + if ((cnt = card->rcvidx[channel])) { + if (!(skb = dev_alloc_skb(cnt))) { + printk(KERN_WARNING "ïcn: receive out of memory\n"); + break; + } + memcpy(skb_put(skb, cnt), card->rcvbuf[channel], cnt); + card->rcvidx[channel] = 0; + card->interface.rcvcallb_skb(card->myid, channel, skb); + } + } + if (!icn_trymaplock_channel(card, mch)) + break; + } + icn_maprelease_channel(card, mch & 2); + } } /* Send data-packet to B-Channel, split it up into fragments of * ICN_FRAGSIZE length. If last fragment is sent out, signal * success to upper layers via statcallb with ISDN_STAT_BSENT argument. - * This routine is called via timer-callback from pollbchan() or - * directly from sendbuf(). + * This routine is called via timer-callback from icn_pollbchan() or + * directly from icn_sendbuf(). */ -static void icn_pollbchan_send(int channel, icn_dev * dev) +static void icn_pollbchan_send(int channel, icn_card *card) { - int mch = channel + ((dev->secondhalf) ? 2 : 0); - int eflag = 0; - int cnt; - int left; - int flags; - pqueue *p; - isdn_ctrl cmd; - - if (!dev->sndcount[channel]) - return; - if (icn_trymaplock_channel(mch)) { - while (sbfree && dev->sndcount[channel]) { - left = dev->spqueue[channel]->length; - cnt = - (sbuf_l = - (left > ICN_FRAGSIZE) ? ((sbuf_f = 0xff), ICN_FRAGSIZE) : ((sbuf_f = 0), left)); - memcpy(sbuf_d, dev->spqueue[channel]->rptr, cnt); - sbnext; /* switch to next buffer */ - icn_maprelease_channel(mch & 2); - dev->spqueue[channel]->rptr += cnt; - eflag = ((dev->spqueue[channel]->length -= cnt) == 0); - save_flags(flags); - cli(); - p = dev->spqueue[channel]; - dev->sndcount[channel] -= cnt; - if (eflag) - dev->spqueue[channel] = (pqueue *) dev->spqueue[channel]->next; - restore_flags(flags); - if (eflag) { - kfree_s(p, p->size); - cmd.command = ISDN_STAT_BSENT; - cmd.driver = dev->myid; - cmd.arg = channel; - dev->interface.statcallb(&cmd); - } - if (!icn_trymaplock_channel(mch)) - break; - } - icn_maprelease_channel(mch & 2); - } + int mch = channel + ((card->secondhalf) ? 2 : 0); + int cnt; + unsigned long flags; + struct sk_buff *skb; + isdn_ctrl cmd; + + if (!card->sndcount[channel]) + return; + if (icn_trymaplock_channel(card,mch)) { + while (sbfree && card->sndcount[channel]) { + save_flags(flags); + cli(); + skb = skb_peek(&card->spqueue[channel]); + if (!skb) { + restore_flags(flags); + break; + } + if (skb->lock) { + restore_flags(flags); + break; + } + skb->lock = 1; + restore_flags(flags); + cnt = + (sbuf_l = + (skb->len > ICN_FRAGSIZE) ? ((sbuf_f = 0xff), ICN_FRAGSIZE) : ((sbuf_f = 0), skb->len)); + memcpy(sbuf_d, skb->data, cnt); + skb_pull(skb, cnt); + card->sndcount[channel] -= cnt; + sbnext; /* switch to next buffer */ + icn_maprelease_channel(card, mch & 2); + if (!skb->len) { + skb = skb_dequeue(&card->spqueue[channel]); + skb->free = 1; + skb->lock = 0; + kfree_skb(skb, FREE_WRITE); + cmd.command = ISDN_STAT_BSENT; + cmd.driver = card->myid; + cmd.arg = channel; + card->interface.statcallb(&cmd); + } else + skb->lock = 0; + if (!icn_trymaplock_channel(card, mch)) + break; + } + icn_maprelease_channel(card, mch & 2); + } } /* Send/Receive Data to/from the B-Channel. @@ -401,253 +402,56 @@ static void icn_pollbchan_send(int channel, icn_dev * dev) * It schedules itself while any B-Channel is open. */ -static void icn_pollbchan(unsigned long dummy) +static void icn_pollbchan(unsigned long data) { - unsigned long flags; - - dev->flags |= ICN_FLAGS_RBTIMER; - if (dev->flags & ICN_FLAGS_B1ACTIVE) { - icn_pollbchan_receive(0, dev); - icn_pollbchan_send(0, dev); - } - if (dev->flags & ICN_FLAGS_B2ACTIVE) { - icn_pollbchan_receive(1, dev); - icn_pollbchan_send(1, dev); - } - if (dev->doubleS0) { - if (dev2->flags & ICN_FLAGS_B1ACTIVE) { - icn_pollbchan_receive(0, dev2); - icn_pollbchan_send(0, dev2); - } - if (dev2->flags & ICN_FLAGS_B2ACTIVE) { - icn_pollbchan_receive(1, dev2); - icn_pollbchan_send(1, dev2); - } - } - if (dev->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) { - /* schedule b-channel polling again */ - save_flags(flags); - cli(); - del_timer(&dev->rb_timer); - dev->rb_timer.function = icn_pollbchan; - dev->rb_timer.expires = jiffies + ICN_TIMER_BCREAD; - add_timer(&dev->rb_timer); - restore_flags(flags); - } else - dev->flags &= ~ICN_FLAGS_RBTIMER; - if (dev->doubleS0) { - if (dev2->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) { - /* schedule b-channel polling again */ - save_flags(flags); - cli(); - del_timer(&dev2->rb_timer); - dev2->rb_timer.function = icn_pollbchan; - dev2->rb_timer.expires = jiffies + ICN_TIMER_BCREAD; - add_timer(&dev2->rb_timer); - restore_flags(flags); - } else - dev2->flags &= ~ICN_FLAGS_RBTIMER; - } + icn_card *card = (icn_card *)data; + unsigned long flags; + + if (card->flags & ICN_FLAGS_B1ACTIVE) { + icn_pollbchan_receive(0, card); + icn_pollbchan_send(0, card); + } + if (card->flags & ICN_FLAGS_B2ACTIVE) { + icn_pollbchan_receive(1, card); + icn_pollbchan_send(1, card); + } + if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) { + /* schedule b-channel polling again */ + save_flags(flags); + cli(); + card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD; + add_timer(&card->rb_timer); + card->flags |= ICN_FLAGS_RBTIMER; + restore_flags(flags); + } else + card->flags &= ~ICN_FLAGS_RBTIMER; } -static void icn_pollit(icn_dev * dev) -{ - int mch = dev->secondhalf ? 2 : 0; - int avail = 0; - int dflag = 0; - int left; - u_char c; - int ch; - int flags; - int i; - u_char *p; - isdn_ctrl cmd; - - if (icn_trymaplock_channel(mch)) { - avail = msg_avail; - for (left = avail, i = msg_o; left > 0; i++, left--) { - c = dev->shmem->comm_buffers.iopc_buf[i & 0xff]; - save_flags(flags); - cli(); - *dev->msg_buf_write++ = (c == 0xff) ? '\n' : c; - if (dev->msg_buf_write == dev->msg_buf_read) { - if (++dev->msg_buf_read > dev->msg_buf_end) - dev->msg_buf_read = dev->msg_buf; - } - if (dev->msg_buf_write > dev->msg_buf_end) - dev->msg_buf_write = dev->msg_buf; - restore_flags(flags); - if (c == 0xff) { - dev->imsg[dev->iptr] = 0; - dev->iptr = 0; - if (dev->imsg[0] == '0' && dev->imsg[1] >= '0' && - dev->imsg[1] <= '2' && dev->imsg[2] == ';') { - ch = dev->imsg[1] - '0'; - p = &dev->imsg[3]; - if (!strncmp(p, "BCON_", 5)) { - switch (ch) { - case 1: - dev->flags |= ICN_FLAGS_B1ACTIVE; - break; - case 2: - dev->flags |= ICN_FLAGS_B2ACTIVE; - break; - } - cmd.command = ISDN_STAT_BCONN; - cmd.driver = dev->myid; - cmd.arg = ch - 1; - dev->interface.statcallb(&cmd); - continue; - } - if (!strncmp(p, "TEI OK", 6)) { - cmd.command = ISDN_STAT_RUN; - cmd.driver = dev->myid; - cmd.arg = ch - 1; - dev->interface.statcallb(&cmd); - continue; - } - if (!strncmp(p, "BDIS_", 5)) { - switch (ch) { - case 1: - dev->flags &= ~ICN_FLAGS_B1ACTIVE; - dflag |= 1; - break; - case 2: - dev->flags &= ~ICN_FLAGS_B2ACTIVE; - dflag |= 2; - break; - } - cmd.command = ISDN_STAT_BHUP; - cmd.arg = ch - 1; - cmd.driver = dev->myid; - dev->interface.statcallb(&cmd); - continue; - } - if (!strncmp(p, "DCON_", 5)) { - cmd.command = ISDN_STAT_DCONN; - cmd.arg = ch - 1; - cmd.driver = dev->myid; - dev->interface.statcallb(&cmd); - continue; - } - if (!strncmp(p, "DDIS_", 5)) { - cmd.command = ISDN_STAT_DHUP; - cmd.arg = ch - 1; - cmd.driver = dev->myid; - dev->interface.statcallb(&cmd); - continue; - } - if (!strncmp(p, "E_L1: ACT FAIL", 14)) { - cmd.command = ISDN_STAT_BHUP; - cmd.arg = 0; - cmd.driver = dev->myid; - dev->interface.statcallb(&cmd); - cmd.command = ISDN_STAT_DHUP; - cmd.arg = 0; - cmd.driver = dev->myid; - dev->interface.statcallb(&cmd); - continue; - } - if (!strncmp(p, "CIF", 3)) { - cmd.command = ISDN_STAT_CINF; - cmd.arg = ch - 1; - strncpy(cmd.num, p + 3, sizeof(cmd.num) - 1); - cmd.driver = dev->myid; - dev->interface.statcallb(&cmd); - continue; - } - if (!strncmp(p, "CAU", 3)) { - cmd.command = ISDN_STAT_CAUSE; - cmd.arg = ch - 1; - strncpy(cmd.num, p + 3, sizeof(cmd.num) - 1); - cmd.driver = dev->myid; - dev->interface.statcallb(&cmd); - continue; - } - if (!strncmp(p, "DCAL_I", 6)) { - cmd.command = ISDN_STAT_ICALL; - cmd.driver = dev->myid; - cmd.arg = ch - 1; - strncpy(cmd.num, p + 6, sizeof(cmd.num) - 1); - dev->interface.statcallb(&cmd); - continue; - } - if (!strncmp(p, "FCALL", 5)) { - cmd.command = ISDN_STAT_ICALL; - cmd.driver = dev->myid; - cmd.arg = ch - 1; - strcpy(cmd.num, "LEASED,07,00,1"); - dev->interface.statcallb(&cmd); - continue; - } - if (!strncmp(p, "DSCA_I", 6)) { - cmd.command = ISDN_STAT_ICALL; - cmd.driver = dev->myid; - cmd.arg = ch - 1; - strncpy(cmd.num, p + 6, sizeof(cmd.num) - 1); - dev->interface.statcallb(&cmd); - continue; - } - if (!strncmp(p, "NO D-CHAN", 9)) { - cmd.command = ISDN_STAT_NODCH; - cmd.driver = dev->myid; - cmd.arg = ch - 1; - strncpy(cmd.num, p + 6, sizeof(cmd.num) - 1); - dev->interface.statcallb(&cmd); - continue; - } - } else { - p = dev->imsg; - if (!strncmp(p, "DRV1.", 5)) { - printk(KERN_INFO "icn: %s\n",p); - if (!strncmp(p + 7, "TC", 2)) { - dev->ptype = ISDN_PTYPE_1TR6; - dev->interface.features |= ISDN_FEATURE_P_1TR6; - printk(KERN_INFO "icn: 1TR6-Protocol loaded and running\n"); - } - if (!strncmp(p + 7, "EC", 2)) { - dev->ptype = ISDN_PTYPE_EURO; - dev->interface.features |= ISDN_FEATURE_P_EURO; - printk(KERN_INFO "icn: Euro-Protocol loaded and running\n"); - } - continue; - } - } - } else { - dev->imsg[dev->iptr] = c; - if (dev->iptr < 59) - dev->iptr++; - } - } - msg_o = (msg_o + avail) & 0xff; - icn_release_channel(); - } - if (avail) { - cmd.command = ISDN_STAT_STAVAIL; - cmd.driver = dev->myid; - cmd.arg = avail; - dev->interface.statcallb(&cmd); - } - if (dflag & 1) - dev->interface.rcvcallb(dev->myid, 0, dev->rcvbuf[0], 0); - if (dflag & 2) - dev->interface.rcvcallb(dev->myid, 1, dev->rcvbuf[1], 0); - if (dev->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) - if (!(dev->flags & ICN_FLAGS_RBTIMER)) { - /* schedule b-channel polling */ - dev->flags |= ICN_FLAGS_RBTIMER; - save_flags(flags); - cli(); - del_timer(&dev->rb_timer); - dev->rb_timer.function = icn_pollbchan; - dev->rb_timer.expires = jiffies + ICN_TIMER_BCREAD; - add_timer(&dev->rb_timer); - restore_flags(flags); - } -} +typedef struct icn_stat { + char *statstr; + int command; + int action; +} icn_stat; + +static icn_stat icn_stat_table[] = { + {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */ + {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */ + {"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */ + {"DDIS_", ISDN_STAT_DHUP, 0}, /* D-Channel disconnected */ + {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */ + {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */ + {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */ + {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */ + {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */ + {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */ + {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */ + {"NO D-CHAN", ISDN_STAT_NODCH, 0}, /* No D-channel available */ + {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */ + {NULL, 0 , -1} +}; /* - * Check Statusqueue-Pointer from isdn-card. + * Check Statusqueue-Pointer from isdn-cards. * If there are new status-replies from the interface, check * them against B-Channel-connects/disconnects and set flags accordingly. * Wake-Up any processes, who are reading the status-device. @@ -656,93 +460,260 @@ static void icn_pollit(icn_dev * dev) * This routine is called periodically via timer. */ -static void icn_pollcard(unsigned long dummy) +static int icn_parse_status(u_char *status, int channel, icn_card *card) +{ + icn_stat *s = icn_stat_table; + int action = -1; + int dflag = 0; + unsigned long flags; + isdn_ctrl cmd; + + while (s->statstr) { + if (!strncmp(status,s->statstr,strlen(s->statstr))) { + cmd.command = s->command; + action = s->action; + break; + } + s++; + } + if (action==-1) + return 0; + cmd.driver = card->myid; + cmd.arg = channel; + switch (action) { + case 1: + card->flags |= (channel)? + ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE; + break; + case 2: + card->flags &= ~((channel)? + ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE); + icn_free_queue(&card->spqueue[channel]); + save_flags(flags); + cli(); + card->rcvidx[channel] = 0; + restore_flags(flags); + dflag |= (channel+1); + break; + case 3: + strncpy(cmd.num, status + 6, sizeof(cmd.num) - 1); + break; + case 4: + sprintf(cmd.num,"LEASED%d,07,00,%d", + card->myid,channel+1); + break; + case 5: + strncpy(cmd.num, status + 3, sizeof(cmd.num) - 1); + break; + case 6: + sprintf(cmd.num,"%d", + (int)simple_strtoul(status + 7,NULL,16)); + break; + case 7: + status += 3; + if (strlen(status)==4) + sprintf(cmd.num,"%s%c%c", + status+2,*status,*(status+1)); + else + strncpy(cmd.num, status+1, sizeof(cmd.num) - 1); + break; + case 8: + cmd.arg = 0; + cmd.driver = card->myid; + card->interface.statcallb(&cmd); + cmd.command = ISDN_STAT_DHUP; + cmd.arg = 0; + cmd.driver = card->myid; + card->interface.statcallb(&cmd); + cmd.command = ISDN_STAT_BHUP; + cmd.arg = 1; + cmd.driver = card->myid; + card->interface.statcallb(&cmd); + cmd.command = ISDN_STAT_DHUP; + cmd.arg = 1; + cmd.driver = card->myid; + break; + } + card->interface.statcallb(&cmd); + return dflag; +} + +static void icn_polldchan(unsigned long data) { - ulong flags; - - icn_pollit(dev); - if (dev->doubleS0) - icn_pollit(dev2); - /* schedule again */ - save_flags(flags); - cli(); - del_timer(&dev->st_timer); - dev->st_timer.function = icn_pollcard; - dev->st_timer.expires = jiffies + ICN_TIMER_DCREAD; - add_timer(&dev->st_timer); - restore_flags(flags); + icn_card *card = (icn_card *)data; + int mch = card->secondhalf ? 2 : 0; + int avail = 0; + int dflag = 0; + int left; + u_char c; + int ch; + int flags; + int i; + u_char *p; + isdn_ctrl cmd; + + if (icn_trymaplock_channel(card,mch)) { + avail = msg_avail; + for (left = avail, i = msg_o; left > 0; i++, left--) { + c = dev.shmem->comm_buffers.iopc_buf[i & 0xff]; + save_flags(flags); + cli(); + *card->msg_buf_write++ = (c == 0xff) ? '\n' : c; + if (card->msg_buf_write == card->msg_buf_read) { + if (++card->msg_buf_read > card->msg_buf_end) + card->msg_buf_read = card->msg_buf; + } + if (card->msg_buf_write > card->msg_buf_end) + card->msg_buf_write = card->msg_buf; + restore_flags(flags); + if (c == 0xff) { + card->imsg[card->iptr] = 0; + card->iptr = 0; + if (card->imsg[0] == '0' && card->imsg[1] >= '0' && + card->imsg[1] <= '2' && card->imsg[2] == ';') { + ch = (card->imsg[1] - '0') - 1; + p = &card->imsg[3]; + dflag |= icn_parse_status(p, ch, card); + } else { + p = card->imsg; + if (!strncmp(p, "DRV1.", 5)) { + u_char vstr[10]; + u_char *q = vstr; + + printk(KERN_INFO "icn: (%s) %s\n",CID,p); + if (!strncmp(p + 7, "TC", 2)) { + card->ptype = ISDN_PTYPE_1TR6; + card->interface.features |= ISDN_FEATURE_P_1TR6; + printk(KERN_INFO + "icn: (%s) 1TR6-Protocol loaded and running\n",CID); + } + if (!strncmp(p + 7, "EC", 2)) { + card->ptype = ISDN_PTYPE_EURO; + card->interface.features |= ISDN_FEATURE_P_EURO; + printk(KERN_INFO + "icn: (%s) Euro-Protocol loaded and running\n",CID); + } + p = strstr(card->imsg,"BRV") + 3; + while (*p) { + if (*p>='0' && *p<='9') + *q++ = *p; + p++; + } + *q = '\0'; + strcat(vstr,"000"); + vstr[3] = '\0'; + card->fw_rev = (int)simple_strtoul(vstr,NULL,10); + continue; + + } + } + } else { + card->imsg[card->iptr] = c; + if (card->iptr < 59) + card->iptr++; + } + } + msg_o = (msg_o + avail) & 0xff; + icn_release_channel(); + } + if (avail) { + cmd.command = ISDN_STAT_STAVAIL; + cmd.driver = card->myid; + cmd.arg = avail; + card->interface.statcallb(&cmd); + } + if (dflag & 1) + card->interface.rcvcallb(card->myid, 0, card->rcvbuf[0], 0); + if (dflag & 2) + card->interface.rcvcallb(card->myid, 1, card->rcvbuf[1], 0); + if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) + if (!(card->flags & ICN_FLAGS_RBTIMER)) { + /* schedule b-channel polling */ + card->flags |= ICN_FLAGS_RBTIMER; + save_flags(flags); + cli(); + del_timer(&card->rb_timer); + card->rb_timer.function = icn_pollbchan; + card->rb_timer.data = (unsigned long)card; + card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD; + add_timer(&card->rb_timer); + restore_flags(flags); + } + /* schedule again */ + save_flags(flags); + cli(); + card->st_timer.expires = jiffies + ICN_TIMER_DCREAD; + add_timer(&card->st_timer); + restore_flags(flags); } -/* Send a packet to the transmit-buffers, handle fragmentation if necessary. +/* Append a packet to the transmit buffer-queue. * Parameters: - * channel = Number of B-channel - * buffer = pointer to packet - * len = size of packet (max 4000) - * dev = pointer to device-struct - * user = 1 = call from userproc, 0 = call from kernel + * channel = Number of B-channel + * buffer = pointer to packet + * len = size of packet (max 4000) + * user = 1 = call from userproc, 0 = call from kernel + * card = pointer to card-struct * Return: - * Number of bytes transferred, -E??? on error + * Number of bytes transferred, -E??? on error */ -static int icn_sendbuf(int channel, const u_char * buffer, int len, int user, icn_dev * dev) +static int icn_sendbuf(int channel, struct sk_buff *skb, icn_card * card) { - register u_char *p; - int flags; - - if (len > 4000) - return -EINVAL; - if (len) { - if (dev->sndcount[channel] > ICN_MAX_SQUEUE) - return 0; - save_flags(flags); - cli(); - p = icn_new_buf(&dev->spqueue[channel], len); - if (!p) { - restore_flags(flags); - return 0; - } - if (user) { - memcpy_fromfs(p, buffer, len); - } else { - memcpy(p, buffer, len); - } - dev->sndcount[channel] += len; - icn_pollbchan_send(channel, dev); - restore_flags(flags); - } - return len; + int len = skb->len; + unsigned long flags; + + if (len > 4000) { + skb->free = 1; + kfree_skb(skb, FREE_WRITE); + return -EINVAL; + } + if (len) { + if (!(card->flags & (channel)?ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE)) + return 0; + if (card->sndcount[channel] > ICN_MAX_SQUEUE) + return 0; + save_flags(flags); + cli(); + card->sndcount[channel] += len; + skb_queue_tail(&card->spqueue[channel], skb); + restore_flags(flags); + icn_pollbchan_send(channel, card); + } + return len; } -#ifndef LOADEXTERN static int icn_check_loader(int cardnumber) { - int timer = 0; + int timer = 0; - while (1) { + while (1) { #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Loader %d ?\n", cardnumber); + printk(KERN_DEBUG "Loader %d ?\n", cardnumber); #endif - if (dev->shmem->data_control.scns || - dev->shmem->data_control.scnr) { - if (timer++ > 5) { - printk(KERN_WARNING "icn: Boot-Loader %d timed out.\n", cardnumber); - icn_release_channel(); - return -EIO; - } + if (dev.shmem->data_control.scns || + dev.shmem->data_control.scnr) { + if (timer++ > 5) { + printk(KERN_WARNING + "icn: Boot-Loader %d timed out.\n", + cardnumber); + icn_release_channel(); + return -EIO; + } #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Loader %d TO?\n", cardnumber); + printk(KERN_DEBUG "Loader %d TO?\n", cardnumber); #endif - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + ICN_BOOT_TIMEOUT1; - schedule(); - } else { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + ICN_BOOT_TIMEOUT1; + schedule(); + } else { #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Loader %d OK\n", cardnumber); + printk(KERN_DEBUG "Loader %d OK\n", cardnumber); #endif - icn_release_channel(); - return 0; - } - } + icn_release_channel(); + return 0; + } + } } /* Load the boot-code into the interface-card's memory and start it. @@ -769,585 +740,782 @@ int slsec = sec; \ #define SLEEP(sec) #endif -static int icn_loadboot(u_char * buffer, icn_dev * dev) +static int icn_loadboot(u_char * buffer, icn_card * card) { - int ret; - ulong flags; + int ret; + ulong flags; #ifdef BOOT_DEBUG - printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer); + printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer); #endif - if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE1))) - return ret; - save_flags(flags); - cli(); - if (!dev->rvalid) { - if (check_region(dev->port, ICN_PORTLEN)) { - printk(KERN_WARNING "icn: ports 0x%03x-0x%03x in use.\n", dev->port, - dev->port + ICN_PORTLEN); - restore_flags(flags); - return -EBUSY; - } - request_region(dev->port, ICN_PORTLEN, regname); - dev->rvalid = 1; - } - if (!dev->mvalid) { - if (check_shmem((ulong) dev->shmem, 0x4000)) { - printk(KERN_WARNING "icn: memory at 0x%08lx in use.\n", (ulong) dev->shmem); - restore_flags(flags); - return -EBUSY; - } - request_shmem((ulong) dev->shmem, 0x4000, regname); - dev->mvalid = 1; - } - restore_flags(flags); - OUTB_P(0, ICN_RUN); /* Reset Controller */ - OUTB_P(0, ICN_MAPRAM); /* Disable RAM */ - icn_shiftout(ICN_CFG, 0x0f, 3, 4); /* Windowsize= 16k */ - icn_shiftout(ICN_CFG, (unsigned long) dev->shmem, 23, 10); /* Set RAM-Addr. */ + if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE1))) + return ret; + save_flags(flags); + cli(); + if (!card->rvalid) { + if (check_region(card->port, ICN_PORTLEN)) { + printk(KERN_WARNING + "icn: (%s) ports 0x%03x-0x%03x in use.\n", + CID, + card->port, + card->port + ICN_PORTLEN); + restore_flags(flags); + return -EBUSY; + } + request_region(card->port, ICN_PORTLEN, card->regname); + card->rvalid = 1; + if (card->doubleS0) + card->other->rvalid = 1; + } + if (!dev.mvalid) { + if (check_shmem((ulong) dev.shmem, 0x4000)) { + printk(KERN_WARNING + "icn: memory at 0x%08lx in use.\n", + (ulong) dev.shmem); + restore_flags(flags); + return -EBUSY; + } + request_shmem((ulong) dev.shmem, 0x4000, "icn"); + dev.mvalid = 1; + } + restore_flags(flags); + OUTB_P(0, ICN_RUN); /* Reset Controller */ + OUTB_P(0, ICN_MAPRAM); /* Disable RAM */ + icn_shiftout(ICN_CFG, 0x0f, 3, 4); /* Windowsize= 16k */ + icn_shiftout(ICN_CFG, (unsigned long) dev.shmem, 23, 10); /* Set RAM-Addr. */ #ifdef BOOT_DEBUG - printk(KERN_DEBUG "shmem=%08lx\n", (ulong) dev->shmem); + printk(KERN_DEBUG "shmem=%08lx\n", (ulong) dev.shmem); #endif - SLEEP(1); - save_flags(flags); - cli(); - dev->channel = 1; /* Force Mapping */ + SLEEP(1); + save_flags(flags); + cli(); + dev.channel = 1; /* Force Mapping */ + dev.mcard = NULL; #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Map Bank 0\n"); + printk(KERN_DEBUG "Map Bank 0\n"); #endif - icn_map_channel(0); /* Select Bank 0 */ - icn_lock_channel(0); /* Lock Bank 0 */ - restore_flags(flags); - SLEEP(1); - memcpy_fromfs(dev->shmem, buffer, ICN_CODE_STAGE1); /* Copy code */ + icn_map_channel(card,0); /* Select Bank 0 */ + icn_lock_channel(card,0); /* Lock Bank 0 */ + restore_flags(flags); + SLEEP(1); + memcpy_fromfs(dev.shmem, buffer, ICN_CODE_STAGE1); /* Copy code */ #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Bootloader transfered\n"); + printk(KERN_DEBUG "Bootloader transfered\n"); #endif - if (dev->doubleS0) { - SLEEP(1); - save_flags(flags); - cli(); - icn_release_channel(); + if (card->doubleS0) { + SLEEP(1); + save_flags(flags); + cli(); + icn_release_channel(); #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Map Bank 8\n"); + printk(KERN_DEBUG "Map Bank 8\n"); #endif - icn_map_channel(2); /* Select Bank 8 */ - icn_lock_channel(2); /* Lock Bank 8 */ - restore_flags(flags); - SLEEP(1); - memcpy_fromfs(dev->shmem, buffer, ICN_CODE_STAGE1); /* Copy code */ + icn_map_channel(card,2); /* Select Bank 8 */ + icn_lock_channel(card,2); /* Lock Bank 8 */ + restore_flags(flags); + SLEEP(1); + memcpy_fromfs(dev.shmem, buffer, ICN_CODE_STAGE1); /* Copy code */ #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Bootloader transfered\n"); + printk(KERN_DEBUG "Bootloader transfered\n"); #endif - } - SLEEP(1); - OUTB_P(0xff, ICN_RUN); /* Start Boot-Code */ - if ((ret = icn_check_loader(dev->doubleS0 ? 2 : 1))) - return ret; - if (!dev->doubleS0) - return 0; - /* reached only, if we have a Double-S0-Card */ - save_flags(flags); - cli(); + } + SLEEP(1); + OUTB_P(0xff, ICN_RUN); /* Start Boot-Code */ + if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1))) + return ret; + if (!card->doubleS0) + return 0; + /* reached only, if we have a Double-S0-Card */ + save_flags(flags); + cli(); #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Map Bank 0\n"); + printk(KERN_DEBUG "Map Bank 0\n"); #endif - icn_map_channel(0); /* Select Bank 0 */ - icn_lock_channel(0); /* Lock Bank 0 */ - restore_flags(flags); - SLEEP(1); - return (icn_check_loader(1)); + icn_map_channel(card,0); /* Select Bank 0 */ + icn_lock_channel(card,0); /* Lock Bank 0 */ + restore_flags(flags); + SLEEP(1); + return (icn_check_loader(1)); } -static int icn_loadproto(u_char * buffer, icn_dev * ldev) +static int icn_loadproto(u_char * buffer, icn_card * card) { - register u_char *p = buffer; - uint left = ICN_CODE_STAGE2; - uint cnt; - int timer; - int ret; - unsigned long flags; + register u_char *p = buffer; + uint left = ICN_CODE_STAGE2; + uint cnt; + int timer; + int ret; + unsigned long flags; #ifdef BOOT_DEBUG - printk(KERN_DEBUG "icn_loadproto called\n"); + printk(KERN_DEBUG "icn_loadproto called\n"); #endif - if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE2))) - return ret; - timer = 0; - save_flags(flags); - cli(); - if (ldev->secondhalf) { - icn_map_channel(2); - icn_lock_channel(2); - } else { - icn_map_channel(0); - icn_lock_channel(0); - } - restore_flags(flags); - while (left) { - if (sbfree) { /* If there is a free buffer... */ - cnt = MIN(256, left); - memcpy_fromfs(&sbuf_l, p, cnt); /* copy data */ - sbnext; /* switch to next buffer */ - p += cnt; - left -= cnt; - timer = 0; - } else { + if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE2))) + return ret; + timer = 0; + save_flags(flags); + cli(); + if (card->secondhalf) { + icn_map_channel(card, 2); + icn_lock_channel(card, 2); + } else { + icn_map_channel(card, 0); + icn_lock_channel(card, 0); + } + restore_flags(flags); + while (left) { + if (sbfree) { /* If there is a free buffer... */ + cnt = MIN(256, left); + memcpy_fromfs(&sbuf_l, p, cnt); /* copy data */ + sbnext; /* switch to next buffer */ + p += cnt; + left -= cnt; + timer = 0; + } else { #ifdef BOOT_DEBUG - printk(KERN_DEBUG "boot 2 !sbfree\n"); + printk(KERN_DEBUG "boot 2 !sbfree\n"); #endif - if (timer++ > 5) { - icn_maprelease_channel(0); - return -EIO; - } - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 10; - schedule(); - } - } - sbuf_n = 0x20; - timer = 0; - while (1) { - if (cmd_o || cmd_i) { + if (timer++ > 5) { + icn_maprelease_channel(card, 0); + return -EIO; + } + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 10; + schedule(); + } + } + sbuf_n = 0x20; + timer = 0; + while (1) { + if (cmd_o || cmd_i) { #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Proto?\n"); + printk(KERN_DEBUG "Proto?\n"); #endif - if (timer++ > 5) { - printk(KERN_WARNING "icn: Protocol timed out.\n"); + if (timer++ > 5) { + printk(KERN_WARNING + "icn: (%s) Protocol timed out.\n", + CID); #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Proto TO!\n"); + printk(KERN_DEBUG "Proto TO!\n"); #endif - icn_maprelease_channel(0); - return -EIO; - } + icn_maprelease_channel(card, 0); + return -EIO; + } #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Proto TO?\n"); + printk(KERN_DEBUG "Proto TO?\n"); #endif - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + ICN_BOOT_TIMEOUT1; - schedule(); - } else { - if ((ldev->secondhalf) || (!dev->doubleS0)) { - save_flags(flags); - cli(); + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + ICN_BOOT_TIMEOUT1; + schedule(); + } else { + if ((card->secondhalf) || (!card->doubleS0)) { + save_flags(flags); + cli(); #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n", - ldev->secondhalf); + printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n", + card->secondhalf); #endif - init_timer(&dev->st_timer); - dev->st_timer.expires = jiffies + ICN_TIMER_DCREAD; - dev->st_timer.function = icn_pollcard; - add_timer(&dev->st_timer); - restore_flags(flags); - } - icn_maprelease_channel(0); - return 0; - } - } + init_timer(&card->st_timer); + card->st_timer.expires = jiffies + ICN_TIMER_DCREAD; + card->st_timer.function = icn_polldchan; + card->st_timer.data = (unsigned long)card; + add_timer(&card->st_timer); + card->flags |= ICN_FLAGS_RUNNING; + if (card->doubleS0) { + init_timer(&card->other->st_timer); + card->other->st_timer.expires = jiffies + ICN_TIMER_DCREAD; + card->other->st_timer.function = icn_polldchan; + card->other->st_timer.data = (unsigned long)card->other; + add_timer(&card->other->st_timer); + card->other->flags |= ICN_FLAGS_RUNNING; + } + restore_flags(flags); + } + icn_maprelease_channel(card, 0); + return 0; + } + } } -#endif /* !LOADEXTERN */ /* Read the Status-replies from the Interface */ -static int icn_readstatus(u_char * buf, int len, int user, icn_dev * dev) +static int icn_readstatus(u_char * buf, int len, int user, icn_card * card) { - int count; - u_char *p; + int count; + u_char *p; - for (p = buf, count = 0; count < len; p++, count++) { - if (dev->msg_buf_read == dev->msg_buf_write) + for (p = buf, count = 0; count < len; p++, count++) { + if (card->msg_buf_read == card->msg_buf_write) return count; - if (user) - put_fs_byte(*dev->msg_buf_read++, p); - else - *p = *dev->msg_buf_read++; - if (dev->msg_buf_read > dev->msg_buf_end) - dev->msg_buf_read = dev->msg_buf; - } - return count; + if (user) + put_fs_byte(*card->msg_buf_read++, p); + else + *p = *card->msg_buf_read++; + if (card->msg_buf_read > card->msg_buf_end) + card->msg_buf_read = card->msg_buf; + } + return count; } /* Put command-strings into the command-queue of the Interface */ -static int icn_writecmd(const u_char * buf, int len, int user, icn_dev * dev, int waitflg) +static int icn_writecmd(const u_char * buf, int len, int user, icn_card * card, int waitflg) { - int mch = dev->secondhalf ? 2 : 0; - int avail; - int pp; - int i; - int count; - int ocount; - unsigned long flags; - u_char *p; - isdn_ctrl cmd; - u_char msg[0x100]; - - while (1) { - if (icn_trymaplock_channel(mch)) { - avail = cmd_free; - count = MIN(avail, len); - if (user) - memcpy_fromfs(msg, buf, count); - else - memcpy(msg, buf, count); - save_flags(flags); - cli(); - ocount = 1; - *dev->msg_buf_write++ = '>'; - if (dev->msg_buf_write > dev->msg_buf_end) - dev->msg_buf_write = dev->msg_buf; - for (p = msg, pp = cmd_i, i = count; i > 0; i--, p++, pp++) { - dev->shmem->comm_buffers.pcio_buf[pp & 0xff] = (*p == '\n') ? 0xff : *p; - *dev->msg_buf_write++ = *p; - if ((*p == '\n') && (i > 1)) { - *dev->msg_buf_write++ = '>'; - if (dev->msg_buf_write > dev->msg_buf_end) - dev->msg_buf_write = dev->msg_buf; - ocount++; - } - /* No checks for buffer overflow of raw-status-device */ - if (dev->msg_buf_write > dev->msg_buf_end) - dev->msg_buf_write = dev->msg_buf; - ocount++; - } - restore_flags(flags); - cmd.command = ISDN_STAT_STAVAIL; - cmd.driver = dev->myid; - cmd.arg = ocount; - dev->interface.statcallb(&cmd); - cmd_i = (cmd_i + count) & 0xff; - icn_release_channel(); - waitflg = 0; - } else - count = 0; - if (!waitflg) - break; - current->timeout = jiffies + 10; - schedule(); - } - return count; + int mch = card->secondhalf ? 2 : 0; + int avail; + int pp; + int i; + int count; + int ocount; + unsigned long flags; + u_char *p; + isdn_ctrl cmd; + u_char msg[0x100]; + + while (1) { + if (icn_trymaplock_channel(card, mch)) { + avail = cmd_free; + count = MIN(avail, len); + if (user) + memcpy_fromfs(msg, buf, count); + else + memcpy(msg, buf, count); + save_flags(flags); + cli(); + ocount = 1; + *card->msg_buf_write++ = '>'; + if (card->msg_buf_write > card->msg_buf_end) + card->msg_buf_write = card->msg_buf; + for (p = msg, pp = cmd_i, i = count; i > 0; i--, p++, pp++) { + dev.shmem->comm_buffers.pcio_buf[pp & 0xff] = (*p == '\n') ? 0xff : *p; + *card->msg_buf_write++ = *p; + if ((*p == '\n') && (i > 1)) { + *card->msg_buf_write++ = '>'; + if (card->msg_buf_write > card->msg_buf_end) + card->msg_buf_write = card->msg_buf; + ocount++; + } + /* No checks for buffer overflow of raw-status-device */ + if (card->msg_buf_write > card->msg_buf_end) + card->msg_buf_write = card->msg_buf; + ocount++; + } + restore_flags(flags); + cmd.command = ISDN_STAT_STAVAIL; + cmd.driver = card->myid; + cmd.arg = ocount; + card->interface.statcallb(&cmd); + cmd_i = (cmd_i + count) & 0xff; + icn_release_channel(); + waitflg = 0; + } else + count = 0; + if (!waitflg) + break; + current->timeout = jiffies + 10; + schedule(); + } + return count; } -static void icn_stopdriver(icn_dev * ldev) +/* + * Delete card's pending timers, send STOP to linklevel + */ +static void icn_stopcard(icn_card * card) { - unsigned long flags; - isdn_ctrl cmd; - - save_flags(flags); - cli(); - del_timer(&dev->st_timer); - del_timer(&ldev->rb_timer); - cmd.command = ISDN_STAT_STOP; - cmd.driver = ldev->myid; - ldev->interface.statcallb(&cmd); - restore_flags(flags); + unsigned long flags; + isdn_ctrl cmd; + + save_flags(flags); + cli(); + if (card->flags & ICN_FLAGS_RUNNING) { + card->flags &= ~ICN_FLAGS_RUNNING; + del_timer(&card->st_timer); + del_timer(&card->rb_timer); + cmd.command = ISDN_STAT_STOP; + cmd.driver = card->myid; + card->interface.statcallb(&cmd); + if (card->doubleS0) + icn_stopcard(card->other); + } + restore_flags(flags); } -static int my_atoi(char *s) +static void icn_stopallcards(void) { - int i, n; - - n = 0; - if (!s) - return -1; - for (i = 0; *s >= '0' && *s <= '9'; i++, s++) - n = 10 * n + (*s - '0'); - return n; + icn_card *p = cards; + + while (p) { + icn_stopcard(p); + p = p->next; + } } -static int icn_command(isdn_ctrl * c, icn_dev * ldev) +static int icn_command(isdn_ctrl * c, icn_card * card) { - ulong a; - ulong flags; - int i; - char cbuf[60]; - isdn_ctrl cmd; - - switch (c->command) { - case ISDN_CMD_IOCTL: - memcpy(&a, c->num, sizeof(ulong)); - switch (c->arg) { - case ICN_IOCTL_SETMMIO: - if ((unsigned long) dev->shmem != (a & 0x0ffc000)) { - if (check_shmem((ulong) (a & 0x0ffc000), 0x4000)) { - printk(KERN_WARNING "icn: memory at 0x%08lx in use.\n", - (ulong) (a & 0x0ffc000)); - return -EINVAL; - } - icn_stopdriver(dev); - if (dev->doubleS0) - icn_stopdriver(dev2); - save_flags(flags); - cli(); - if (dev->mvalid) - release_shmem((ulong) dev->shmem, 0x4000); - dev->mvalid = 0; - dev->shmem = (icn_shmem *) (a & 0x0ffc000); - if (dev->doubleS0) - dev2->shmem = (icn_shmem *) (a & 0x0ffc000); - restore_flags(flags); - printk(KERN_INFO "icn: mmio set to 0x%08lx\n", - (unsigned long) dev->shmem); - } - break; - case ICN_IOCTL_GETMMIO: - return (int) dev->shmem; - case ICN_IOCTL_SETPORT: - if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330 - || a == 0x340 || a == 0x350 || a == 0x360 || - a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338 - || a == 0x348 || a == 0x358 || a == 0x368) { - if (dev->port != (unsigned short) a) { - if (check_region((unsigned short) a, ICN_PORTLEN)) { - printk(KERN_WARNING "icn: ports 0x%03x-0x%03x in use.\n", - (int) a, (int) a + ICN_PORTLEN); - return -EINVAL; - } - icn_stopdriver(dev); - if (dev->doubleS0) - icn_stopdriver(dev2); - save_flags(flags); - cli(); - if (dev->rvalid) - release_region(dev->port, ICN_PORTLEN); - dev->port = (unsigned short) a; - dev->rvalid = 0; - if (dev->doubleS0) { - dev2->port = (unsigned short) a; - dev2->rvalid = 0; - } - restore_flags(flags); - printk(KERN_INFO "icn: port set to 0x%03x\n", dev->port); - } - } else - return -EINVAL; - break; - case ICN_IOCTL_GETPORT: - return (int) dev->port; - case ICN_IOCTL_GETDOUBLE: - return (int) dev->doubleS0; - case ICN_IOCTL_DEBUGVAR: - return (ulong) ldev; -#ifndef LOADEXTERN - case ICN_IOCTL_LOADBOOT: - icn_stopdriver(dev); - if (dev->doubleS0) - icn_stopdriver(dev2); - return (icn_loadboot((u_char *) a, dev)); - case ICN_IOCTL_LOADPROTO: - icn_stopdriver(dev); - if (dev->doubleS0) - icn_stopdriver(dev2); - if ((i = (icn_loadproto((u_char *) a, dev)))) - return i; - if (dev->doubleS0) - i = icn_loadproto((u_char *) (a + ICN_CODE_STAGE2), dev2); - return i; -#endif - case ICN_IOCTL_LEASEDCFG: - if (a) { - if (!ldev->leased) { - ldev->leased = 1; - while (ldev->ptype == ISDN_PTYPE_UNKNOWN) { - current->timeout = jiffies + ICN_BOOT_TIMEOUT1; - schedule(); - } - current->timeout = jiffies + ICN_BOOT_TIMEOUT1; - schedule(); - sprintf(cbuf, "00;FV2ON\n01;EAZ1\n"); - i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1); - printk(KERN_INFO "icn: Leased-line mode enabled\n"); - cmd.command = ISDN_STAT_RUN; - cmd.driver = ldev->myid; - cmd.arg = 0; - ldev->interface.statcallb(&cmd); - } - } else { - if (ldev->leased) { - ldev->leased = 0; - sprintf(cbuf, "00;FV2OFF\n"); - i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1); - printk(KERN_INFO "icn: Leased-line mode disabled\n"); - cmd.command = ISDN_STAT_RUN; - cmd.driver = ldev->myid; - cmd.arg = 0; - ldev->interface.statcallb(&cmd); - } - } - return 0; - default: - return -EINVAL; - } - break; - case ISDN_CMD_DIAL: - if (ldev->leased) - break; - if ((c->arg & 255) < ICN_BCH) { - char *p; - char *p2; - char dial[50]; - char sis[50]; - char dcode[4]; - int si1, si2; - - a = c->arg; - strcpy(sis, c->num); - p = strrchr(sis, ','); - *p++ = '\0'; - si2 = my_atoi(p); - p = strrchr(sis, ',') + 1; - si1 = my_atoi(p); - p = c->num; - if (*p == 's' || *p == 'S') { - /* Dial for SPV */ - p++; - strcpy(dcode, "SCA"); - } else - /* Normal Dial */ - strcpy(dcode, "CAL"); - strcpy(dial, p); - p = strchr(dial, ','); - *p++ = '\0'; - p2 = strchr(p, ','); - *p2 = '\0'; - sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), dcode, dial, si1, - si2, p); - i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1); - } - break; - case ISDN_CMD_ACCEPTD: - if (c->arg < ICN_BCH) { - a = c->arg + 1; - sprintf(cbuf, "%02d;DCON_R\n", (int) a); - i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1); - } - break; - case ISDN_CMD_ACCEPTB: - if (c->arg < ICN_BCH) { - a = c->arg + 1; - sprintf(cbuf, "%02d;BCON_R\n", (int) a); - i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1); - } - break; - case ISDN_CMD_HANGUP: - if (c->arg < ICN_BCH) { - a = c->arg + 1; - sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a); - i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1); - } - break; - case ISDN_CMD_SETEAZ: - if (ldev->leased) - break; - if (c->arg < ICN_BCH) { - a = c->arg + 1; - if (ldev->ptype == ISDN_PTYPE_EURO) { - sprintf(cbuf, "%02d;MS%s%s\n", (int) a, c->num[0] ? "N" : "ALL", c->num); - } else - sprintf(cbuf, "%02d;EAZ%s\n", (int) a, c->num[0] ? c->num : "0123456789"); - i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1); - } - break; - case ISDN_CMD_CLREAZ: - if (ldev->leased) - break; - if (c->arg < ICN_BCH) { - a = c->arg + 1; - if (ldev->ptype == ISDN_PTYPE_EURO) - sprintf(cbuf, "%02d;MSNC\n", (int) a); - else - sprintf(cbuf, "%02d;EAZC\n", (int) a); - i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1); - } - break; - case ISDN_CMD_SETL2: - if ((c->arg & 255) < ICN_BCH) { - a = c->arg; - switch (a >> 8) { - case ISDN_PROTO_L2_X75I: - sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1); - break; - case ISDN_PROTO_L2_HDLC: - sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1); - break; - default: - return -EINVAL; - } - i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1); - ldev->l2_proto[a & 255] = (a >> 8); - } - break; - case ISDN_CMD_GETL2: - if ((c->arg & 255) < ICN_BCH) - return ldev->l2_proto[c->arg & 255]; - else - return -ENODEV; - case ISDN_CMD_SETL3: - return 0; - case ISDN_CMD_GETL3: - if ((c->arg & 255) < ICN_BCH) - return ISDN_PROTO_L3_TRANS; - else - return -ENODEV; - case ISDN_CMD_GETEAZ: - break; - case ISDN_CMD_SETSIL: - break; - case ISDN_CMD_GETSIL: - break; - case ISDN_CMD_LOCK: - MOD_INC_USE_COUNT; - break; - case ISDN_CMD_UNLOCK: - MOD_DEC_USE_COUNT; - break; - default: - return -EINVAL; - } - return 0; + ulong a; + ulong flags; + int i; + char cbuf[60]; + isdn_ctrl cmd; + icn_cdef cdef; + + switch (c->command) { + case ISDN_CMD_IOCTL: + memcpy(&a, c->num, sizeof(ulong)); + switch (c->arg) { + case ICN_IOCTL_SETMMIO: + if ((unsigned long) dev.shmem != (a & 0x0ffc000)) { + if (check_shmem((ulong) (a & 0x0ffc000), 0x4000)) { + printk(KERN_WARNING + "icn: memory at 0x%08lx in use.\n", + (ulong) (a & 0x0ffc000)); + return -EINVAL; + } + icn_stopallcards(); + save_flags(flags); + cli(); + if (dev.mvalid) + release_shmem((ulong) dev.shmem, 0x4000); + dev.mvalid = 0; + dev.shmem = (icn_shmem *) (a & 0x0ffc000); + restore_flags(flags); + printk(KERN_INFO + "icn: (%s) mmio set to 0x%08lx\n", + CID, + (unsigned long) dev.shmem); + } + break; + case ICN_IOCTL_GETMMIO: + return (int) dev.shmem; + case ICN_IOCTL_SETPORT: + if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330 + || a == 0x340 || a == 0x350 || a == 0x360 || + a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338 + || a == 0x348 || a == 0x358 || a == 0x368) { + if (card->port != (unsigned short) a) { + if (check_region((unsigned short) a, ICN_PORTLEN)) { + printk(KERN_WARNING + "icn: (%s) ports 0x%03x-0x%03x in use.\n", + CID, (int) a, (int) a + ICN_PORTLEN); + return -EINVAL; + } + icn_stopcard(card); + save_flags(flags); + cli(); + if (card->rvalid) + release_region(card->port, ICN_PORTLEN); + card->port = (unsigned short) a; + card->rvalid = 0; + if (card->doubleS0) { + card->other->port = (unsigned short) a; + card->other->rvalid = 0; + } + restore_flags(flags); + printk(KERN_INFO + "icn: (%s) port set to 0x%03x\n", + CID, card->port); + } + } else + return -EINVAL; + break; + case ICN_IOCTL_GETPORT: + return (int) card->port; + case ICN_IOCTL_GETDOUBLE: + return (int) card->doubleS0; + case ICN_IOCTL_DEBUGVAR: + return (ulong) card; + case ICN_IOCTL_LOADBOOT: + icn_stopcard(card); + return (icn_loadboot((u_char *) a, card)); + case ICN_IOCTL_LOADPROTO: + icn_stopcard(card); + if ((i = (icn_loadproto((u_char *) a, card)))) + return i; + if (card->doubleS0) + i = icn_loadproto((u_char *) (a + ICN_CODE_STAGE2), card->other); + return i; + break; + case ICN_IOCTL_ADDCARD: + if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(icn_cdef)))) + return i; + memcpy_fromfs((char *)&cdef, (char *)a, sizeof(cdef)); + return (icn_addcard(cdef.port, cdef.id1, cdef.id2)); + break; + case ICN_IOCTL_LEASEDCFG: + if (a) { + if (!card->leased) { + card->leased = 1; + while (card->ptype == ISDN_PTYPE_UNKNOWN) { + current->timeout = jiffies + ICN_BOOT_TIMEOUT1; + schedule(); + } + current->timeout = jiffies + ICN_BOOT_TIMEOUT1; + schedule(); + sprintf(cbuf, "00;FV2ON\n01;EAZ1\n"); + i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); + printk(KERN_INFO + "icn: (%s) Leased-line mode enabled\n", + CID); + cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; + cmd.arg = 0; + card->interface.statcallb(&cmd); + } + } else { + if (card->leased) { + card->leased = 0; + sprintf(cbuf, "00;FV2OFF\n"); + i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); + printk(KERN_INFO + "icn: (%s) Leased-line mode disabled\n", + CID); + cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; + cmd.arg = 0; + card->interface.statcallb(&cmd); + } + } + return 0; + default: + return -EINVAL; + } + break; + case ISDN_CMD_DIAL: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if (card->leased) + break; + if ((c->arg & 255) < ICN_BCH) { + char *p; + char *p2; + char dial[50]; + char sis[50]; + char dcode[4]; + int si1, si2; + + a = c->arg; + strcpy(sis, c->num); + p = strrchr(sis, ','); + *p++ = '\0'; + si2 = simple_strtoul(p,NULL,10); + p = strrchr(sis, ',') + 1; + si1 = simple_strtoul(p,NULL,10); + p = c->num; + if (*p == 's' || *p == 'S') { + /* Dial for SPV */ + p++; + strcpy(dcode, "SCA"); + } else + /* Normal Dial */ + strcpy(dcode, "CAL"); + strcpy(dial, p); + p = strchr(dial, ','); + *p++ = '\0'; + p2 = strchr(p, ','); + *p2 = '\0'; + sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), dcode, dial, si1, + si2, p); + i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); + } + break; + case ISDN_CMD_ACCEPTD: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if (c->arg < ICN_BCH) { + a = c->arg + 1; + if (card->fw_rev >= 300) { + switch (card->l2_proto[a-1]) { + case ISDN_PROTO_L2_X75I: + sprintf(cbuf, "%02d;BX75\n", (int) a); + break; + case ISDN_PROTO_L2_HDLC: + sprintf(cbuf, "%02d;BTRA\n", (int) a); + break; + } + i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); + } + sprintf(cbuf, "%02d;DCON_R\n", (int) a); + i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); + } + break; + case ISDN_CMD_ACCEPTB: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if (c->arg < ICN_BCH) { + a = c->arg + 1; + if (card->fw_rev >= 300) + switch (card->l2_proto[a-1]) { + case ISDN_PROTO_L2_X75I: + sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a); + break; + case ISDN_PROTO_L2_HDLC: + sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a); + break; + } + else + sprintf(cbuf, "%02d;BCON_R\n", (int) a); + i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); + } + break; + case ISDN_CMD_HANGUP: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if (c->arg < ICN_BCH) { + a = c->arg + 1; + sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a); + i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); + } + break; + case ISDN_CMD_SETEAZ: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if (card->leased) + break; + if (c->arg < ICN_BCH) { + a = c->arg + 1; + if (card->ptype == ISDN_PTYPE_EURO) { + sprintf(cbuf, "%02d;MS%s%s\n", (int) a, + c->num[0] ? "N" : "ALL", c->num); + } else + sprintf(cbuf, "%02d;EAZ%s\n", (int) a, + c->num[0] ? c->num : "0123456789"); + i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); + } + break; + case ISDN_CMD_CLREAZ: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if (card->leased) + break; + if (c->arg < ICN_BCH) { + a = c->arg + 1; + if (card->ptype == ISDN_PTYPE_EURO) + sprintf(cbuf, "%02d;MSNC\n", (int) a); + else + sprintf(cbuf, "%02d;EAZC\n", (int) a); + i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); + } + break; + case ISDN_CMD_SETL2: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if ((c->arg & 255) < ICN_BCH) { + a = c->arg; + switch (a >> 8) { + case ISDN_PROTO_L2_X75I: + sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1); + break; + case ISDN_PROTO_L2_HDLC: + sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1); + break; + default: + return -EINVAL; + } + i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); + card->l2_proto[a & 255] = (a >> 8); + } + break; + case ISDN_CMD_GETL2: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if ((c->arg & 255) < ICN_BCH) + return card->l2_proto[c->arg & 255]; + else + return -ENODEV; + case ISDN_CMD_SETL3: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + return 0; + case ISDN_CMD_GETL3: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if ((c->arg & 255) < ICN_BCH) + return ISDN_PROTO_L3_TRANS; + else + return -ENODEV; + case ISDN_CMD_GETEAZ: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + break; + case ISDN_CMD_SETSIL: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + break; + case ISDN_CMD_GETSIL: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + break; + case ISDN_CMD_LOCK: + MOD_INC_USE_COUNT; + break; + case ISDN_CMD_UNLOCK: + MOD_DEC_USE_COUNT; + break; + default: + return -EINVAL; + } + return 0; } /* - * For second half of doubleS0-Card add channel-offset. + * Find card with given driverId */ -static int if_command1(isdn_ctrl * c) +static inline icn_card * + icn_findcard(int driverid) { - return (icn_command(c, dev)); + icn_card *p = cards; + + while (p) { + if (p->myid == driverid) + return p; + p = p->next; + } + return (icn_card *)0; } -static int if_command2(isdn_ctrl * c) +/* + * Wrapper functions for interface to linklevel + */ +static int if_command(isdn_ctrl * c) { - return (icn_command(c, dev2)); -} + icn_card *card = icn_findcard(c->driver); -static int if_writecmd1(const u_char * buf, int len, int user) -{ - return (icn_writecmd(buf, len, user, dev, 0)); + if (card) + return (icn_command(c, card)); + printk(KERN_ERR + "icn: if_command called with invalid driverId!\n"); + return -ENODEV; } -static int if_writecmd2(const u_char * buf, int len, int user) +static int if_writecmd(const u_char * buf, int len, int user, int id, int channel) { - return (icn_writecmd(buf, len, user, dev2, 0)); + icn_card *card = icn_findcard(id); + + if (card) { + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + return (icn_writecmd(buf, len, user, card, 0)); + } + printk(KERN_ERR + "icn: if_writecmd called with invalid driverId!\n"); + return -ENODEV; } -static int if_readstatus1(u_char * buf, int len, int user) +static int if_readstatus(u_char * buf, int len, int user, int id, int channel) { - return (icn_readstatus(buf, len, user, dev)); + icn_card *card = icn_findcard(id); + + if (card) { + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + return (icn_readstatus(buf, len, user, card)); + } + printk(KERN_ERR + "icn: if_readstatus called with invalid driverId!\n"); + return -ENODEV; } -static int if_readstatus2(u_char * buf, int len, int user) +static int if_sendbuf(int id, int channel, struct sk_buff *skb) { - return (icn_readstatus(buf, len, user, dev2)); + icn_card *card = icn_findcard(id); + + if (card) { + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + return (icn_sendbuf(channel, skb, card)); + } + printk(KERN_ERR + "icn: if_readstatus called with invalid driverId!\n"); + return -ENODEV; } -static int if_sendbuf1(int id, int channel, const u_char * buffer, int len, - int user) -{ - return (icn_sendbuf(channel, buffer, len, user, dev)); +/* + * Allocate a new card-struct, initialize it + * link it into cards-list and register it at linklevel. + */ +static icn_card *icn_initcard(int port, char *id) { + icn_card *card; + int i; + + if (!(card = (icn_card *) kmalloc(sizeof(icn_card), GFP_KERNEL))) { + printk(KERN_WARNING + "icn: (%s) Could not allocate card-struct.\n", id); + return (icn_card *)0; + } + memset((char *) card, 0, sizeof(icn_card)); + card->port = port; + card->interface.channels = ICN_BCH; + card->interface.maxbufsize = 4000; + card->interface.command = if_command; + /* + card->interface.writebuf = if_sendbuf; + */ + card->interface.writebuf_skb = if_sendbuf; + card->interface.writecmd = if_writecmd; + card->interface.readstat = if_readstatus; + card->interface.features = ISDN_FEATURE_L2_X75I | + ISDN_FEATURE_L2_HDLC | + ISDN_FEATURE_L3_TRANS | + ISDN_FEATURE_P_UNKNOWN; + card->ptype = ISDN_PTYPE_UNKNOWN; + strncpy(card->interface.id, id, sizeof(card->interface.id) - 1); + card->msg_buf_write = card->msg_buf; + card->msg_buf_read = card->msg_buf; + card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1]; + for (i=0;il2_proto[i] = ISDN_PROTO_L2_X75I; + skb_queue_head_init(&card->spqueue[i]); + } + card->next = cards; + cards = card; + if (!register_isdn(&card->interface)) { + cards = cards->next; + printk(KERN_WARNING + "icn: Unable to register %s\n", id); + kfree(card); + return (icn_card*)0; + } + card->myid = card->interface.channels; + sprintf(card->regname, "icn-isdn (%s)", card->interface.id); + return card; } -static int if_sendbuf2(int id, int channel, const u_char * buffer, int len, - int user) +static int icn_addcard(int port, char *id1, char *id2) { - return (icn_sendbuf(channel, buffer, len, user, dev2)); + ulong flags; + icn_card *card; + icn_card *card2; + + save_flags(flags); + cli(); + if (!(card = icn_initcard(port,id1))) { + restore_flags(flags); + return -EIO; + } + if (!strlen(id2)) { + restore_flags(flags); + printk(KERN_INFO + "icn: (%s) ICN-2B, port 0x%x added\n", + card->interface.id, port); + return 0; + } + if (!(card2 = icn_initcard(port,id2))) { + restore_flags(flags); + printk(KERN_INFO + "icn: (%s) half ICN-4B, port 0x%x added\n", + card2->interface.id, port); + return 0; + } + card->doubleS0 = 1; + card->secondhalf = 0; + card->other = card2; + card2->doubleS0 = 1; + card2->secondhalf = 1; + card2->other = card; + restore_flags(flags); + printk(KERN_INFO + "icn: (%s and %s) ICN-4B, port 0x%x added\n", + card->interface.id, card2->interface.id, port); + return 0; } #ifdef MODULE @@ -1355,158 +1523,81 @@ static int if_sendbuf2(int id, int channel, const u_char * buffer, int len, #else void icn_setup(char *str, int *ints) { - char *p; - static char sid[20]; - static char sid2[20]; - - if (ints[0]) - portbase = ints[1]; - if (ints[0]>1) - membase = ints[2]; - if (strlen(str)) { - strcpy(sid,str); - icn_id = sid; - if ((p = strchr(sid,','))) { - *p++ = 0; - strcpy(sid2,p); - icn_id2 = sid2; - } - } + char *p; + static char sid[20]; + static char sid2[20]; + + if (ints[0]) + portbase = ints[1]; + if (ints[0]>1) + membase = ints[2]; + if (strlen(str)) { + strcpy(sid,str); + icn_id = sid; + if ((p = strchr(sid,','))) { + *p++ = 0; + strcpy(sid2,p); + icn_id2 = sid2; + } + } } #endif int icn_init(void) { -#ifdef LOADEXTERN - unsigned long flags; -#endif - char *p; - isdn_ctrl cmd; - char rev[10]; - - if (!(dev = (icn_devptr) kmalloc(sizeof(icn_dev), GFP_KERNEL))) { - printk(KERN_WARNING "icn: Could not allocate device-struct.\n"); - return -EIO; - } - memset((char *) dev, 0, sizeof(icn_dev)); - dev->port = portbase; - dev->shmem = (icn_shmem *) (membase & 0x0ffc000); - if (strlen(icn_id2)) - dev->doubleS0 = 1; - dev->interface.channels = ICN_BCH; - dev->interface.maxbufsize = 4000; - dev->interface.command = if_command1; - dev->interface.writebuf = if_sendbuf1; - dev->interface.writecmd = if_writecmd1; - dev->interface.readstat = if_readstatus1; - dev->interface.features = ISDN_FEATURE_L2_X75I | - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L3_TRANS | - ISDN_FEATURE_P_UNKNOWN; - dev->ptype = ISDN_PTYPE_UNKNOWN; - strncpy(dev->interface.id, icn_id, sizeof(dev->interface.id) - 1); - dev->msg_buf_write = dev->msg_buf; - dev->msg_buf_read = dev->msg_buf; - dev->msg_buf_end = &dev->msg_buf[sizeof(dev->msg_buf) - 1]; - memset((char *) dev->l2_proto, ISDN_PROTO_L2_X75I, sizeof(dev->l2_proto)); - if (strlen(icn_id2)) { - if (!(dev2 = (icn_devptr) kmalloc(sizeof(icn_dev), GFP_KERNEL))) { - printk(KERN_WARNING "icn: Could not allocate device-struct.\n"); - kfree(dev); - kfree(dev2); - return -EIO; - } - memcpy((char *) dev2, (char *) dev, sizeof(icn_dev)); - dev2->interface.command = if_command2; - dev2->interface.writebuf = if_sendbuf2; - dev2->interface.writecmd = if_writecmd2; - dev2->interface.readstat = if_readstatus2; - strncpy(dev2->interface.id, icn_id2, - sizeof(dev->interface.id) - 1); - dev2->msg_buf_write = dev2->msg_buf; - dev2->msg_buf_read = dev2->msg_buf; - dev2->msg_buf_end = &dev2->msg_buf[sizeof(dev2->msg_buf) - 1]; - dev2->secondhalf = 1; - } - if (!register_isdn(&dev->interface)) { - printk(KERN_WARNING "icn: Unable to register\n"); - kfree(dev); - if (dev->doubleS0) - kfree(dev2); - return -EIO; - } - dev->myid = dev->interface.channels; - sprintf(regname, "icn-isdn (%s)", dev->interface.id); - if (dev->doubleS0) { - if (!register_isdn(&dev2->interface)) { - printk(KERN_WARNING "icn: Unable to register\n"); - kfree(dev2); - if (dev->doubleS0) { - icn_stopdriver(dev); - cmd.command = ISDN_STAT_UNLOAD; - cmd.driver = dev->myid; - dev->interface.statcallb(&cmd); - kfree(dev); - } - return -EIO; - } - dev2->myid = dev2->interface.channels; - } - - /* No symbols to export, hide all symbols */ - register_symtab(NULL); - - if ((p = strchr(revision, ':'))) { - strcpy(rev, p + 1); - p = strchr(rev, '$'); - *p = 0; - } else - strcpy(rev, " ??? "); - printk(KERN_NOTICE "ICN-ISDN-driver Rev%sport=0x%03x mmio=0x%08x id='%s'\n", - rev, dev->port, (uint) dev->shmem, dev->interface.id); -#ifdef LOADEXTERN - save_flags(flags); - cli(); - init_timer(&dev->st_timer); - dev->st_timer.expires = jiffies + ICN_TIMER_DCREAD; - dev->st_timer.function = icn_pollcard; - add_timer(&dev->st_timer); - restore_flags(flags); -#endif - return 0; + char *p; + char rev[10]; + + memset(&dev, 0, sizeof(icn_dev)); + dev.shmem = (icn_shmem *) (membase & 0x0ffc000); + + /* No symbols to export, hide all symbols */ + register_symtab(NULL); + + if ((p = strchr(revision, ':'))) { + strcpy(rev, p + 1); + p = strchr(rev, '$'); + *p = 0; + } else + strcpy(rev, " ??? "); + printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08x\n", rev, + (uint) dev.shmem); + return (icn_addcard(portbase,icn_id,icn_id2)); } #ifdef MODULE void cleanup_module(void) { - isdn_ctrl cmd; - int i; - - icn_stopdriver(dev); - cmd.command = ISDN_STAT_UNLOAD; - cmd.driver = dev->myid; - dev->interface.statcallb(&cmd); - if (dev->doubleS0) { - icn_stopdriver(dev2); - cmd.command = ISDN_STAT_UNLOAD; - cmd.driver = dev2->myid; - dev2->interface.statcallb(&cmd); - } - if (dev->rvalid) { - OUTB_P(0, ICN_RUN); /* Reset Controller */ - OUTB_P(0, ICN_MAPRAM); /* Disable RAM */ - release_region(dev->port, ICN_PORTLEN); - } - if (dev->mvalid) - release_shmem((ulong) dev->shmem, 0x4000); - if (dev->doubleS0) { - for (i = 0; i < ICN_BCH; i++) - icn_free_queue(&dev2->spqueue[1]); - kfree(dev2); - } - for (i = 0; i < ICN_BCH; i++) - icn_free_queue(&dev->spqueue[1]); - kfree(dev); - printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n"); + isdn_ctrl cmd; + icn_card *card = cards; + icn_card *last; + int i; + + icn_stopallcards(); + while (card) { + cmd.command = ISDN_STAT_UNLOAD; + cmd.driver = card->myid; + card->interface.statcallb(&cmd); + if (card->rvalid) { + OUTB_P(0, ICN_RUN); /* Reset Controller */ + OUTB_P(0, ICN_MAPRAM); /* Disable RAM */ + if (card->secondhalf || (!card->doubleS0)) { + release_region(card->port, ICN_PORTLEN); + card->rvalid = 0; + } + for (i = 0; i < ICN_BCH; i++) + icn_free_queue(&card->spqueue[i]); + } + card = card->next; + } + card = card; + while (card) { + last = card; + card = card->next; + kfree(last); + } + if (dev.mvalid) + release_shmem((ulong) dev.shmem, 0x4000); + printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n"); } #endif diff --git a/drivers/isdn/icn/icn.h b/drivers/isdn/icn/icn.h index 7e690a297c81..86d44b329bf7 100644 --- a/drivers/isdn/icn/icn.h +++ b/drivers/isdn/icn/icn.h @@ -1,4 +1,4 @@ -/* $Id: icn.h,v 1.13 1996/04/20 16:51:41 fritz Exp $ +/* $Id: icn.h,v 1.17 1996/05/18 00:47:04 fritz Exp $ * * ISDN lowlevel-module for the ICN active ISDN-Card. * @@ -19,6 +19,21 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.h,v $ + * Revision 1.17 1996/05/18 00:47:04 fritz + * Removed callback debug code. + * + * Revision 1.16 1996/05/17 15:46:43 fritz + * Removed own queue management. + * Changed queue management to use sk_buffs. + * + * Revision 1.15 1996/05/02 04:01:57 fritz + * Removed ICN_MAXCARDS + * + * Revision 1.14 1996/05/02 00:40:29 fritz + * Major rewrite to support more than one card + * with a single module. + * Support for new firmware. + * * Revision 1.13 1996/04/20 16:51:41 fritz * Increased status buffer. * Misc. typos @@ -75,6 +90,14 @@ #define ICN_IOCTL_LEASEDCFG 6 #define ICN_IOCTL_GETDOUBLE 7 #define ICN_IOCTL_DEBUGVAR 8 +#define ICN_IOCTL_ADDCARD 9 + +/* Struct for adding new cards */ +typedef struct icn_cdef { + int port; + char id1[10]; + char id2[10]; +} icn_cdef; #if defined(__KERNEL__) || defined(__DEBUGVAR__) @@ -98,7 +121,7 @@ #include #include -#endif /* __KERNEL__ */ +#endif /* __KERNEL__ */ /* some useful macros for debugging */ #ifdef ICN_DEBUG_PORT @@ -112,177 +135,190 @@ #define ICN_PORTLEN (0x04) #define ICN_MEMADDR 0x0d0000 -/* Macros for accessing ports */ -#define ICN_CFG (dev->port) -#define ICN_MAPRAM (dev->port+1) -#define ICN_RUN (dev->port+2) -#define ICN_BANK (dev->port+3) - -#define ICN_FLAGS_B1ACTIVE 1 /* B-Channel-1 is open */ -#define ICN_FLAGS_B2ACTIVE 2 /* B-Channel-2 is open */ -#define ICN_FLAGS_RBTIMER 8 /* cyclic scheduling of B-Channel-poll */ +#define ICN_FLAGS_B1ACTIVE 1 /* B-Channel-1 is open */ +#define ICN_FLAGS_B2ACTIVE 2 /* B-Channel-2 is open */ +#define ICN_FLAGS_RUNNING 4 /* Cards driver activated */ +#define ICN_FLAGS_RBTIMER 8 /* cyclic scheduling of B-Channel-poll */ -#define ICN_BOOT_TIMEOUT1 100 /* Delay for Boot-download (jiffies) */ -#define ICN_CHANLOCK_DELAY 10 /* Delay for Channel-mapping (jiffies) */ +#define ICN_BOOT_TIMEOUT1 100 /* Delay for Boot-download (jiffies) */ +#define ICN_CHANLOCK_DELAY 10 /* Delay for Channel-mapping (jiffies) */ -#define ICN_TIMER_BCREAD 3 /* B-Channel poll-cycle */ -#define ICN_TIMER_DCREAD 50 /* D-Channel poll-cycle */ +#define ICN_TIMER_BCREAD 3 /* B-Channel poll-cycle */ +#define ICN_TIMER_DCREAD 50 /* D-Channel poll-cycle */ -#define ICN_CODE_STAGE1 4096 /* Size of bootcode */ -#define ICN_CODE_STAGE2 65536 /* Size of protocol-code */ +#define ICN_CODE_STAGE1 4096 /* Size of bootcode */ +#define ICN_CODE_STAGE2 65536 /* Size of protocol-code */ -#define ICN_MAX_SQUEUE 65536 /* Max. outstanding send-data */ -#define ICN_FRAGSIZE (250) /* Max. size of send-fragments */ -#define ICN_BCH 2 /* Number of supported channels */ +#define ICN_MAX_SQUEUE 65536 /* Max. outstanding send-data */ +#define ICN_FRAGSIZE (250) /* Max. size of send-fragments */ +#define ICN_BCH 2 /* Number of supported channels per card */ /* type-definitions for accessing the mmap-io-areas */ -#define SHM_DCTL_OFFSET (0) /* Offset to data-controlstructures in shm */ -#define SHM_CCTL_OFFSET (0x1d2) /* Offset to comm-controlstructures in shm */ -#define SHM_CBUF_OFFSET (0x200) /* Offset to comm-buffers in shm */ -#define SHM_DBUF_OFFSET (0x2000) /* Offset to data-buffers in shm */ +#define SHM_DCTL_OFFSET (0) /* Offset to data-controlstructures in shm */ +#define SHM_CCTL_OFFSET (0x1d2) /* Offset to comm-controlstructures in shm */ +#define SHM_CBUF_OFFSET (0x200) /* Offset to comm-buffers in shm */ +#define SHM_DBUF_OFFSET (0x2000) /* Offset to data-buffers in shm */ +/* + * Layout of card's data buffers + */ typedef struct { - unsigned char length; /* Bytecount of fragment (max 250) */ - unsigned char endflag; /* 0=last frag., 0xff=frag. continued */ - unsigned char data[ICN_FRAGSIZE]; /* The data */ - /* Fill to 256 bytes */ - char unused[0x100 - ICN_FRAGSIZE - 2]; + unsigned char length; /* Bytecount of fragment (max 250) */ + unsigned char endflag; /* 0=last frag., 0xff=frag. continued */ + unsigned char data[ICN_FRAGSIZE]; /* The data */ + /* Fill to 256 bytes */ + char unused[0x100 - ICN_FRAGSIZE - 2]; } frag_buf; +/* + * Layout of card's shared memory + */ typedef union { - struct { - unsigned char scns; /* Index to free SendFrag. */ - unsigned char scnr; /* Index to active SendFrag READONLY */ - unsigned char ecns; /* Index to free RcvFrag. READONLY */ - unsigned char ecnr; /* Index to valid RcvFrag */ - char unused[6]; - unsigned short fuell1; /* Internal Buf Bytecount */ - } data_control; - struct { - char unused[SHM_CCTL_OFFSET]; - unsigned char iopc_i; /* Read-Ptr Status-Queue READONLY */ - unsigned char iopc_o; /* Write-Ptr Status-Queue */ - unsigned char pcio_i; /* Write-Ptr Command-Queue */ - unsigned char pcio_o; /* Read-Ptr Command Queue READONLY */ - } comm_control; - struct { - char unused[SHM_CBUF_OFFSET]; - unsigned char pcio_buf[0x100]; /* Ring-Buffer Command-Queue */ - unsigned char iopc_buf[0x100]; /* Ring-Buffer Status-Queue */ - } comm_buffers; - struct { - char unused[SHM_DBUF_OFFSET]; - frag_buf receive_buf[0x10]; - frag_buf send_buf[0x10]; - } data_buffers; + struct { + unsigned char scns; /* Index to free SendFrag. */ + unsigned char scnr; /* Index to active SendFrag READONLY */ + unsigned char ecns; /* Index to free RcvFrag. READONLY */ + unsigned char ecnr; /* Index to valid RcvFrag */ + char unused[6]; + unsigned short fuell1; /* Internal Buf Bytecount */ + } data_control; + struct { + char unused[SHM_CCTL_OFFSET]; + unsigned char iopc_i; /* Read-Ptr Status-Queue READONLY */ + unsigned char iopc_o; /* Write-Ptr Status-Queue */ + unsigned char pcio_i; /* Write-Ptr Command-Queue */ + unsigned char pcio_o; /* Read-Ptr Command Queue READONLY */ + } comm_control; + struct { + char unused[SHM_CBUF_OFFSET]; + unsigned char pcio_buf[0x100]; /* Ring-Buffer Command-Queue */ + unsigned char iopc_buf[0x100]; /* Ring-Buffer Status-Queue */ + } comm_buffers; + struct { + char unused[SHM_DBUF_OFFSET]; + frag_buf receive_buf[0x10]; + frag_buf send_buf[0x10]; + } data_buffers; } icn_shmem; -/* Sendbuffer-queue-element */ -typedef struct { - char *next; - short length; - short size; - u_char *rptr; - u_char buffer[1]; -} pqueue; - -typedef struct { - unsigned short port; /* Base-port-address */ - icn_shmem *shmem; /* Pointer to memory-mapped-buffers */ - int myid; /* Driver-Nr. assigned by linklevel */ - int rvalid; /* IO-portregion has been requested */ - int mvalid; /* IO-shmem has been requested */ - int leased; /* Flag: This Adapter is connected */ - /* to a leased line */ - unsigned short flags; /* Statusflags */ - int doubleS0; /* Flag: Double-S0-Card */ - int secondhalf; /* Flag: Second half of a doubleS0 */ - int ptype; /* Protocol type (1TR6 or Euro) */ - struct timer_list st_timer; /* Timer for Status-Polls */ - struct timer_list rb_timer; /* Timer for B-Channel-Polls */ - int channel; /* Currently mapped Channel */ - int chanlock; /* Semaphore for Channel-Mapping */ - u_char rcvbuf[ICN_BCH][4096]; /* B-Channel-Receive-Buffers */ - int rcvidx[ICN_BCH]; /* Index for above buffers */ - int l2_proto[ICN_BCH]; /* Current layer-2-protocol */ - isdn_if interface; /* Interface to upper layer */ - int iptr; /* Index to imsg-buffer */ - char imsg[60]; /* Internal buf for status-parsing */ - char msg_buf[2048]; /* Buffer for status-messages */ - char *msg_buf_write; /* Writepointer for statusbuffer */ - char *msg_buf_read; /* Readpointer for statusbuffer */ - char *msg_buf_end; /* Pointer to end of statusbuffer */ - int sndcount[ICN_BCH]; /* Byte-counters for B-Ch.-send */ - pqueue *spqueue[ICN_BCH]; /* Pointers to start of Send-Queue */ -#ifdef DEBUG_RCVCALLBACK - int akt_pending[ICN_BCH]; - int max_pending[ICN_BCH]; -#endif +/* + * Per card driver data + */ +typedef struct icn_card { + struct icn_card *next; /* Pointer to next device struct */ + struct icn_card *other; /* Pointer to other card for ICN4B */ + unsigned short port; /* Base-port-address */ + int myid; /* Driver-Nr. assigned by linklevel */ + int rvalid; /* IO-portregion has been requested */ + int leased; /* Flag: This Adapter is connected */ + /* to a leased line */ + unsigned short flags; /* Statusflags */ + int doubleS0; /* Flag: ICN4B */ + int secondhalf; /* Flag: Second half of a doubleS0 */ + int fw_rev; /* Firmware revision loaded */ + int ptype; /* Protocol type (1TR6 or Euro) */ + struct timer_list st_timer; /* Timer for Status-Polls */ + struct timer_list rb_timer; /* Timer for B-Channel-Polls */ + u_char rcvbuf[ICN_BCH][4096]; /* B-Channel-Receive-Buffers */ + int rcvidx[ICN_BCH]; /* Index for above buffers */ + int l2_proto[ICN_BCH]; /* Current layer-2-protocol */ + isdn_if interface; /* Interface to upper layer */ + int iptr; /* Index to imsg-buffer */ + char imsg[60]; /* Internal buf for status-parsing */ + char msg_buf[2048]; /* Buffer for status-messages */ + char *msg_buf_write; /* Writepointer for statusbuffer */ + char *msg_buf_read; /* Readpointer for statusbuffer */ + char *msg_buf_end; /* Pointer to end of statusbuffer */ + int sndcount[ICN_BCH]; /* Byte-counters for B-Ch.-send */ + struct sk_buff_head + spqueue[ICN_BCH]; /* Sendqueue */ + char regname[35]; /* Name used for request_region */ +} icn_card; + +/* + * Main driver data + */ +typedef struct icn_dev { + icn_shmem *shmem; /* Pointer to memory-mapped-buffers */ + int mvalid; /* IO-shmem has been requested */ + int channel; /* Currently mapped channel */ + struct icn_card *mcard; /* Currently mapped card */ + int chanlock; /* Semaphore for channel-mapping */ } icn_dev; typedef icn_dev *icn_devptr; #ifdef __KERNEL__ -static icn_dev *dev = (icn_dev *) 0; -static icn_dev *dev2 = (icn_dev *) 0; + +static icn_card *cards = (icn_card *) 0; +static u_char chan2bank[] = { 0, 4, 8, 12 }; /* for icn_map_channel() */ + +static icn_dev dev; /* With modutils >= 1.1.67 Integers can be changed while loading a * module. For this reason define the Port-Base an Shmem-Base as * integers. */ -int portbase = ICN_BASEADDR; -int membase = ICN_MEMADDR; -char *icn_id = "\0"; +int portbase = ICN_BASEADDR; +int membase = ICN_MEMADDR; +char *icn_id = "\0"; char *icn_id2 = "\0"; -static char regname[35]; /* Name used for port/mem-registration */ -#endif /* __KERNEL__ */ +#endif /* __KERNEL__ */ /* Utility-Macros */ +/* Macros for accessing ports */ +#define ICN_CFG (card->port) +#define ICN_MAPRAM (card->port+1) +#define ICN_RUN (card->port+2) +#define ICN_BANK (card->port+3) + /* Return true, if there is a free transmit-buffer */ -#define sbfree (((dev->shmem->data_control.scns+1) & 0xf) != \ - dev->shmem->data_control.scnr) +#define sbfree (((dev.shmem->data_control.scns+1) & 0xf) != \ + dev.shmem->data_control.scnr) /* Switch to next transmit-buffer */ -#define sbnext (dev->shmem->data_control.scns = \ - ((dev->shmem->data_control.scns+1) & 0xf)) +#define sbnext (dev.shmem->data_control.scns = \ + ((dev.shmem->data_control.scns+1) & 0xf)) /* Shortcuts for transmit-buffer-access */ -#define sbuf_n dev->shmem->data_control.scns -#define sbuf_d dev->shmem->data_buffers.send_buf[sbuf_n].data -#define sbuf_l dev->shmem->data_buffers.send_buf[sbuf_n].length -#define sbuf_f dev->shmem->data_buffers.send_buf[sbuf_n].endflag +#define sbuf_n dev.shmem->data_control.scns +#define sbuf_d dev.shmem->data_buffers.send_buf[sbuf_n].data +#define sbuf_l dev.shmem->data_buffers.send_buf[sbuf_n].length +#define sbuf_f dev.shmem->data_buffers.send_buf[sbuf_n].endflag /* Return true, if there is receive-data is available */ -#define rbavl (dev->shmem->data_control.ecnr != \ - dev->shmem->data_control.ecns) +#define rbavl (dev.shmem->data_control.ecnr != \ + dev.shmem->data_control.ecns) /* Switch to next receive-buffer */ -#define rbnext (dev->shmem->data_control.ecnr = \ - ((dev->shmem->data_control.ecnr+1) & 0xf)) +#define rbnext (dev.shmem->data_control.ecnr = \ + ((dev.shmem->data_control.ecnr+1) & 0xf)) /* Shortcuts for receive-buffer-access */ -#define rbuf_n dev->shmem->data_control.ecnr -#define rbuf_d dev->shmem->data_buffers.receive_buf[rbuf_n].data -#define rbuf_l dev->shmem->data_buffers.receive_buf[rbuf_n].length -#define rbuf_f dev->shmem->data_buffers.receive_buf[rbuf_n].endflag +#define rbuf_n dev.shmem->data_control.ecnr +#define rbuf_d dev.shmem->data_buffers.receive_buf[rbuf_n].data +#define rbuf_l dev.shmem->data_buffers.receive_buf[rbuf_n].length +#define rbuf_f dev.shmem->data_buffers.receive_buf[rbuf_n].endflag /* Shortcuts for command-buffer-access */ -#define cmd_o (dev->shmem->comm_control.pcio_o) -#define cmd_i (dev->shmem->comm_control.pcio_i) +#define cmd_o (dev.shmem->comm_control.pcio_o) +#define cmd_i (dev.shmem->comm_control.pcio_i) /* Return free space in command-buffer */ #define cmd_free ((cmd_i>=cmd_o)?0x100-cmd_i+cmd_o:cmd_o-cmd_i) /* Shortcuts for message-buffer-access */ -#define msg_o (dev->shmem->comm_control.iopc_o) -#define msg_i (dev->shmem->comm_control.iopc_i) +#define msg_o (dev.shmem->comm_control.iopc_o) +#define msg_i (dev.shmem->comm_control.iopc_i) /* Return length of Message, if avail. */ #define msg_avail ((msg_o>msg_i)?0x100-msg_o+msg_i:msg_i-msg_o) +#define CID (card->interface.id) + #define MIN(a,b) ((ab)?a:b) @@ -294,5 +330,5 @@ static char regname[35]; /* Name used for port/mem-registration */ #define release_shmem release_region #define request_shmem request_region -#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */ -#endif /* icn_h */ +#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */ +#endif /* icn_h */ diff --git a/drivers/isdn/isdn_audio.c b/drivers/isdn/isdn_audio.c new file mode 100644 index 000000000000..b53149a99d18 --- /dev/null +++ b/drivers/isdn/isdn_audio.c @@ -0,0 +1,428 @@ +/* $Id: isdn_audio.c,v 1.4 1996/05/17 03:48:01 fritz Exp $ + * + * Linux ISDN subsystem, audio conversion and compression (linklevel). + * + * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Log: isdn_audio.c,v $ + * Revision 1.4 1996/05/17 03:48:01 fritz + * Removed some test statements. + * Added revision string. + * + * Revision 1.3 1996/05/10 08:48:11 fritz + * Corrected adpcm bugs. + * + * Revision 1.2 1996/04/30 09:31:17 fritz + * General rewrite. + * + * Revision 1.1.1.1 1996/04/28 12:25:40 fritz + * Taken under CVS control + * + */ + +#define __NO_VERSION__ +#include +#include +#include "isdn_audio.h" + +char *isdn_audio_revision = "$Revision: 1.4 $"; + +/* + * Misc. lookup-tables. + */ + +/* ulaw -> signed 16-bit */ +static short isdn_audio_ulaw_to_s16[] = { + 0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84, + 0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84, + 0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84, + 0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84, + 0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804, + 0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004, + 0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444, + 0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844, + 0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64, + 0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64, + 0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74, + 0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74, + 0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc, + 0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c, + 0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0, + 0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000, + 0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c, + 0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c, + 0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c, + 0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c, + 0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc, + 0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc, + 0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc, + 0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc, + 0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c, + 0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c, + 0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c, + 0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c, + 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, + 0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084, + 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, + 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 +}; + +/* alaw -> signed 16-bit */ +static short isdn_audio_alaw_to_s16[] = { + 0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4, + 0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74, + 0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4, + 0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64, + 0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4, + 0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4, + 0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4, + 0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4, + 0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64, + 0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34, + 0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844, + 0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24, + 0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64, + 0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4, + 0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964, + 0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4, + 0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24, + 0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94, + 0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924, + 0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94, + 0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24, + 0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14, + 0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24, + 0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14, + 0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4, + 0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54, + 0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4, + 0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64, + 0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4, + 0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4, + 0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4, + 0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4 +}; + +/* alaw -> ulaw */ +static char isdn_audio_alaw_to_ulaw[] = { + 0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49, + 0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57, + 0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41, + 0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f, + 0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d, + 0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b, + 0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45, + 0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53, + 0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47, + 0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55, + 0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f, + 0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e, + 0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b, + 0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59, + 0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43, + 0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51, + 0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a, + 0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58, + 0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42, + 0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50, + 0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e, + 0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c, + 0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46, + 0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54, + 0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48, + 0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56, + 0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40, + 0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f, + 0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c, + 0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a, + 0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44, + 0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52 +}; + +/* ulaw -> alaw */ +static char isdn_audio_ulaw_to_alaw[] = { + 0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35, + 0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25, + 0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d, + 0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d, + 0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31, + 0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21, + 0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9, + 0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9, + 0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47, + 0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf, + 0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f, + 0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33, + 0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23, + 0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b, + 0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b, + 0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b, + 0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34, + 0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24, + 0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c, + 0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c, + 0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30, + 0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20, + 0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8, + 0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8, + 0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46, + 0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde, + 0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e, + 0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32, + 0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22, + 0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a, + 0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a, + 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a +}; + +#if ((CPU == 386) || (CPU == 486) || (CPU == 586)) +static inline void +isdn_audio_tlookup(const void *table, void *buff, unsigned long n) +{ + __asm__("cld\n" + "1:\tlodsb\n\t" + "xlatb\n\t" + "stosb\n\t" + "loop 1b\n\t" + ::"b" ((long)table), "c" (n), "D" ((long)buff), "S" ((long)buff) + :"bx","cx","di","si","ax"); +} +#else +static inline void +isdn_audio_tlookup(const char *table, char *buff, unsigned long n) +{ + while (n--) + *buff++ = table[*buff]; +} +#endif + +void +isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len) +{ + isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len); +} + +void +isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len) +{ + isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len); +} + +/* + * linear <-> adpcm conversion stuff + * Most parts from the mgetty-package. + * (C) by Gert Doering and Klaus Weidner + * Used by permission of Gert Doering + */ + + +#define ZEROTRAP /* turn on the trap as per the MIL-STD */ +#undef ZEROTRAP +#define BIAS 0x84 /* define the add-in bias for 16 bit samples */ +#define CLIP 32635 + +static unsigned char +isdn_audio_linear2ulaw(int sample) { + static int exp_lut[256] = { + 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 + }; + int sign, exponent, mantissa; + unsigned char ulawbyte; + + /* Get the sample into sign-magnitude. */ + sign = (sample >> 8) & 0x80; /* set aside the sign */ + if(sign != 0) sample = -sample; /* get magnitude */ + if(sample > CLIP) sample = CLIP; /* clip the magnitude */ + + /* Convert from 16 bit linear to ulaw. */ + sample = sample + BIAS; + exponent = exp_lut[( sample >> 7 ) & 0xFF]; + mantissa = (sample >> (exponent + 3)) & 0x0F; + ulawbyte = ~(sign | (exponent << 4) | mantissa); +#ifdef ZEROTRAP + /* optional CCITT trap */ + if (ulawbyte == 0) ulawbyte = 0x02; +#endif + return(ulawbyte); +} + + +static int Mx[3][8] = { + { 0x3800, 0x5600, 0,0,0,0,0,0 }, + { 0x399a, 0x3a9f, 0x4d14, 0x6607, 0,0,0,0 }, + { 0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607 }, +}; + +static int bitmask[9] = { + 0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff +}; + +static int +isdn_audio_get_bits (adpcm_state *s, unsigned char **in, int *len) +{ + while( s->nleft < s->nbits) { + int d = *((*in)++); + (*len)--; + s->word = (s->word << 8) | d; + s->nleft += 8; + } + s->nleft -= s->nbits; + return (s->word >> s->nleft) & bitmask[s->nbits]; +} + +static void +isdn_audio_put_bits (int data, int nbits, adpcm_state *s, + unsigned char **out, int *len) +{ + s->word = (s->word << nbits) | (data & bitmask[nbits]); + s->nleft += nbits; + while(s->nleft >= 8) { + int d = (s->word >> (s->nleft-8)); + *(out[0]++) = d & 255; + (*len)++; + s->nleft -= 8; + } +} + +adpcm_state * +isdn_audio_adpcm_init(int nbits) +{ +static adpcm_state *s; + +#ifdef ATEST + s = (adpcm_state *) malloc(sizeof(adpcm_state)); +#else + s = (adpcm_state *) kmalloc(sizeof(adpcm_state), GFP_ATOMIC); +#endif + if (s) { + s->a = 0; + s->d = 5; + s->word = 0; + s->nleft = 0; + s->nbits = nbits; + } + return s; +} + +/* + * Decompression of adpcm data to a/u-law + * + */ + +int +isdn_audio_adpcm2xlaw (adpcm_state *s, int fmt, unsigned char *in, + unsigned char *out, int len) +{ + int a = s->a; + int d = s->d; + int nbits = s->nbits; + int olen = 0; + + while (len) { + int e = isdn_audio_get_bits(s, &in, &len); + int sign; + + if (nbits == 4 && e == 0) + d = 4; + sign = (e >> (nbits-1))?-1:1; + e &= bitmask[nbits-1]; + a += sign * ((e << 1) + 1) * d >> 1; + if (d & 1) + a++; + if (fmt) + *out++ = isdn_audio_ulaw_to_alaw[ + isdn_audio_linear2ulaw(a << 2)]; + else + *out++ = isdn_audio_linear2ulaw(a << 2); + olen++; + d = (d * Mx[nbits-2][ e ] + 0x2000) >> 14; + if ( d < 5 ) + d = 5; + } + s->a = a; + s->d = d; + return olen; +} + +int +isdn_audio_2adpcm_flush (adpcm_state *s, unsigned char *out) +{ + int olen = 0; + + if (s->nleft) + isdn_audio_put_bits(0, 8-s->nleft, s, &out, &olen); + return olen; +} + +int +isdn_audio_xlaw2adpcm (adpcm_state *s, int fmt, unsigned char *in, + unsigned char *out, int len) +{ + int a = s->a; + int d = s->d; + int nbits = s->nbits; + int olen = 0; + + while (len--) { + int e = 0, nmax = 1 << (nbits - 1); + int sign, delta; + + if (fmt) + delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a; + else + delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a; + if (delta < 0) { + e = nmax; + delta = -delta; + } + while( --nmax && delta > d ) { + delta -= d; + e++; + } + if (nbits == 4 && ((e & 0x0f) == 0)) + e = 8; + isdn_audio_put_bits(e, nbits, s, &out, &olen); + sign = (e >> (nbits-1))?-1:1 ; + e &= bitmask[nbits-1]; + + a += sign * ((e << 1) + 1) * d >> 1; + if (d & 1) + a++; + d = (d * Mx[nbits-2][ e ] + 0x2000) >> 14; + if (d < 5) + d=5; + } + s->a = a; + s->d = d; + return olen; +} + diff --git a/drivers/isdn/isdn_audio.h b/drivers/isdn/isdn_audio.h new file mode 100644 index 000000000000..fa7bd1b52067 --- /dev/null +++ b/drivers/isdn/isdn_audio.h @@ -0,0 +1,43 @@ +/* $Id: isdn_audio.h,v 1.2 1996/05/10 08:48:32 fritz Exp $ + * + * Linux ISDN subsystem, audio conversion and compression (linklevel). + * + * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Log: isdn_audio.h,v $ + * Revision 1.2 1996/05/10 08:48:32 fritz + * Corrected adpcm bugs. + * + * Revision 1.1 1996/04/30 09:29:06 fritz + * Taken under CVS control. + * + */ + +typedef struct adpcm_state { + int a; + int d; + int word; + int nleft; + int nbits; +} adpcm_state; + +extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long); +extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long); +extern adpcm_state *isdn_audio_adpcm_init(int); +extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int); +extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int); +extern int isdn_audio_2adpcm_flush(adpcm_state *s, unsigned char *out); diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index 99600a679a67..6cf1d2a2db2b 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.5 1996/04/20 16:19:07 fritz Exp $ +/* $Id: isdn_common.c,v 1.14 1996/05/18 01:36:55 fritz Exp $ * * Linux ISDN subsystem, common used functions (linklevel). * @@ -21,6 +21,39 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.c,v $ + * Revision 1.14 1996/05/18 01:36:55 fritz + * Added spelling corrections and some minor changes + * to stay in sync with kernel. + * + * Revision 1.13 1996/05/17 15:43:30 fritz + * Bugfix: decrement of rcvcount in readbchan() corrected. + * + * Revision 1.12 1996/05/17 03:55:43 fritz + * Changed DLE handling for audio receive. + * Some cleanup. + * Added display of isdn_audio_revision. + * + * Revision 1.11 1996/05/11 21:51:32 fritz + * Changed queue management to use sk_buffs. + * + * Revision 1.10 1996/05/10 08:49:16 fritz + * Checkin before major changes of tty-code. + * + * Revision 1.9 1996/05/07 09:19:41 fritz + * Adapted to changes in isdn_tty.c + * + * Revision 1.8 1996/05/06 11:34:51 hipp + * fixed a few bugs + * + * Revision 1.7 1996/05/02 03:55:17 fritz + * Bugfixes: + * - B-channel connect message for modem devices + * sometimes did not result in a CONNECT-message. + * - register_isdn did not check for driverId-conflicts. + * + * Revision 1.6 1996/04/30 20:57:21 fritz + * Commit test + * * Revision 1.5 1996/04/20 16:19:07 fritz * Changed slow timer handlers to increase accuracy. * Added statistic information for usage by xisdnload. @@ -48,9 +81,7 @@ * */ -#ifndef STANDALONE #include -#endif #include #include #ifndef __GENKSYMS__ /* Don't want genksyms report unneeded structs */ @@ -60,17 +91,18 @@ #include "isdn_tty.h" #include "isdn_net.h" #include "isdn_ppp.h" +#ifdef CONFIG_ISDN_AUDIO +#include "isdn_audio.h" +#endif #include "isdn_cards.h" - - /* Debugflags */ #undef ISDN_DEBUG_STATCALLB isdn_dev *dev = (isdn_dev *) 0; static int has_exported = 0; -static char *isdn_revision = "$Revision: 1.5 $"; +static char *isdn_revision = "$Revision: 1.14 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -79,6 +111,11 @@ extern char *isdn_ppp_revision; #else static char *isdn_ppp_revision = ": none $"; #endif +#ifdef CONFIG_ISDN_AUDIO +extern char *isdn_audio_revision; +#else +static char *isdn_audio_revision = ": none $"; +#endif void isdn_MOD_INC_USE_COUNT(void) { @@ -102,45 +139,23 @@ void isdn_dumppkt(char *s, u_char * p, int len, int dumplen) } #endif -/* Try to allocate a new buffer, link it into queue. */ -u_char * - isdn_new_buf(pqueue ** queue, int length) +static __inline void isdn_trash_skb(struct sk_buff *skb, int rw) { - pqueue *p; - pqueue *q; - - if ((p = *queue)) { - while (p) { - q = p; - p = (pqueue *) p->next; - } - p = (pqueue *) kmalloc(sizeof(pqueue) + length, GFP_ATOMIC); - q->next = (u_char *) p; - } else - p = *queue = (pqueue *) kmalloc(sizeof(pqueue) + length, GFP_ATOMIC); - if (p) { - p->size = sizeof(pqueue) + length; - p->length = length; - p->next = NULL; - p->rptr = p->buffer; - return p->buffer; - } else { - return (u_char *) NULL; - } + skb->free = 1; + kfree_skb(skb, rw); } -static void isdn_free_queue(pqueue ** queue) +static void isdn_free_queue(struct sk_buff_head *queue) { - pqueue *p; - pqueue *q; - - p = *queue; - while (p) { - q = p; - p = (pqueue *) p->next; - kfree_s(q, q->size); - } - *queue = (pqueue *) 0; + struct sk_buff *skb; + unsigned long flags; + + save_flags(flags); + cli(); + if (skb_queue_len(queue)) + while ((skb = skb_dequeue(queue))) + isdn_trash_skb(skb, FREE_READ); + restore_flags(flags); } int isdn_dc2minor(int di, int ch) @@ -222,75 +237,107 @@ void isdn_timer_ctrl(int tf, int onoff) restore_flags(flags); } -/* Receive a packet from B-Channel. (Called from low-level-module) - * Parameters: - * - * di = Driver-Index. - * channel = Number of B-Channel (0...) - * buf = pointer to packet-data - * len = Length of packet-data - * +/* + * Receive a packet from B-Channel. (Called from low-level-module) */ -static void isdn_receive_callback(int di, int channel, u_char * buf, int len) +static void isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb) { ulong flags; - char *p; int i; - int midx; - - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return; - if ((i = isdn_dc2minor(di,channel))==-1) + int midx; + modem_info *info; + + if ((i = isdn_dc2minor(di,channel))==-1) { + isdn_trash_skb(skb, FREE_READ); return; + } /* Update statistics */ - dev->ibytes[i] += len; + dev->ibytes[i] += skb->len; /* First, try to deliver data to network-device */ - if (isdn_net_receive_callback(i, buf, len)) + if (isdn_net_rcv_skb(i, skb)) return; /* No network-device found, deliver to tty or raw-channel */ - if (len) { - save_flags(flags); - cli(); - midx = dev->m_idx[i]; - if (dev->mdm.atmodem[midx].mdmreg[13] & 2) + if (skb->len) { + if ((midx = dev->m_idx[i])<0) { + /* if midx is invalid, drop packet */ + isdn_trash_skb(skb, FREE_READ); + return; + } + info = &dev->mdm.info[midx]; + if ((info->online < 2) && + (info->vonline != 1)) { + /* If Modem not listening, drop data */ + isdn_trash_skb(skb, FREE_READ); + return; + } + if (info->emu.mdmreg[13] & 2) /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */ - if ((buf[0] == 1) && ((buf[1] == 0) || (buf[1] == 1))) { + if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1))) { #ifdef ISDN_DEBUG_MODEM_DUMP - isdn_dumppkt("T70strip1:", buf, len, len); + isdn_dumppkt("T70strip1:", skb->data, skb->len, skb->len); #endif - buf += 4; - len -= 4; + skb_pull(skb,4); #ifdef ISDN_DEBUG_MODEM_DUMP - isdn_dumppkt("T70strip2:", buf, len, len); + isdn_dumppkt("T70strip2:", skb->data, skb->len, skb->len); #endif } + /* The users field of an sk_buff is used in a special way + * with tty's incoming data: + * users is set to the number of DLE codes when in audio mode. + */ + skb->users = 0; +#ifdef CONFIG_ISDN_AUDIO + if (info->vonline == 1) { + int ifmt = 1; + /* voice conversion/compression */ + switch (info->emu.vpar[3]) { + case 2: + case 3: + case 4: + /* adpcm + * Since compressed data takes less + * space, we can overwrite the buffer. + */ + skb_trim(skb,isdn_audio_xlaw2adpcm(info->adpcmr, + ifmt, + skb->data, + skb->data, + skb->len)); + break; + case 5: + /* a-law */ + if (!ifmt) + isdn_audio_ulaw2alaw(skb->data,skb->len); + break; + case 6: + /* u-law */ + if (ifmt) + isdn_audio_alaw2ulaw(skb->data,skb->len); + break; + } + skb->users = isdn_tty_countDLE(skb->data,skb->len); + } +#endif /* Try to deliver directly via tty-flip-buf if queue is empty */ - if (!dev->drv[di]->rpqueue[channel]) - if (isdn_tty_try_read(midx, buf, len)) { + save_flags(flags); + cli(); + if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) + if (isdn_tty_try_read(info, skb)) { restore_flags(flags); return; } /* Direct deliver failed or queue wasn't empty. * Queue up for later dequeueing via timer-irq. */ - p = isdn_new_buf(&dev->drv[di]->rpqueue[channel], len); - if (!p) { - printk(KERN_WARNING "isdn: malloc of rcvbuf failed, dropping.\n"); - dev->drv[di]->rcverr[channel]++; - restore_flags(flags); - return; - } else { - memcpy(p, buf, len); - dev->drv[di]->rcvcount[channel] += len; - } + __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb); + dev->drv[di]->rcvcount[channel] += (skb->len + skb->users); + restore_flags(flags); /* Schedule dequeuing */ - if ((dev->modempoll) && (midx >= 0)) { - if (dev->mdm.rcvsched[midx]) - isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); - } + if ((dev->modempoll) && (info->rcvsched)) + isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]); - restore_flags(flags); - } + } else + isdn_trash_skb(skb, FREE_READ); } void isdn_all_eaz(int di, int ch) @@ -311,6 +358,7 @@ static int isdn_status_callback(isdn_ctrl * c) ulong flags; int i; int r; + modem_info *info; isdn_ctrl cmd; di = c->driver; @@ -323,9 +371,7 @@ static int isdn_status_callback(isdn_ctrl * c) return 0; if (isdn_net_stat_callback(i, c->command)) return 0; -#if FUTURE isdn_tty_bsent(di, c->arg); -#endif wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]); break; case ISDN_STAT_STAVAIL: @@ -366,8 +412,9 @@ static int isdn_status_callback(isdn_ctrl * c) * tty and set RI-bit of modem-status. */ if ((mi = isdn_tty_find_icall(di, c->arg, c->num)) >= 0) { - dev->mdm.msr[mi] |= UART_MSR_RI; - isdn_tty_modem_result(2, &dev->mdm.info[mi]); + info = &dev->mdm.info[mi]; + info->msr |= UART_MSR_RI; + isdn_tty_modem_result(2, info); isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1); } else if (dev->drv[di]->reject_bus) { cmd.driver = di; @@ -428,12 +475,14 @@ static int isdn_status_callback(isdn_ctrl * c) /* Find any network-device, waiting for D-channel setup */ if (isdn_net_stat_callback(i, c->command)) break; - if ((mi = dev->m_idx[i]) >= 0) + + if ((mi = dev->m_idx[i]) >= 0) { /* If any tty has just dialed-out, setup B-Channel */ - if (dev->mdm.info[mi].flags & + info = &dev->mdm.info[mi]; + if (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { - if (dev->mdm.dialing[mi] == 1) { - dev->mdm.dialing[mi] = 2; + if (info->dialing == 1) { + info->dialing = 2; cmd.driver = di; cmd.arg = c->arg; cmd.command = ISDN_CMD_ACCEPTB; @@ -441,6 +490,7 @@ static int isdn_status_callback(isdn_ctrl * c) return 0; } } + } break; case ISDN_STAT_DHUP: if (i<0) @@ -457,19 +507,19 @@ static int isdn_status_callback(isdn_ctrl * c) break; if ((mi = dev->m_idx[i]) >= 0) { /* Signal hangup to tty-device */ - if (dev->mdm.info[mi].flags & + info = &dev->mdm.info[mi]; + if (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { - if (dev->mdm.dialing[mi] == 1) { - dev->mdm.dialing[mi] = 0; - isdn_tty_modem_result(7, &dev->mdm.info[mi]); + if (info->dialing == 1) { + info->dialing = 0; + isdn_tty_modem_result(7, info); } - if (dev->mdm.online[mi]) - isdn_tty_modem_result(3, &dev->mdm.info[mi]); + if (info->online) + isdn_tty_modem_result(3, info); #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n"); #endif - isdn_tty_modem_hup(&dev->mdm.info[mi]); - dev->mdm.msr[mi] &= ~(UART_MSR_DCD | UART_MSR_RI); + isdn_tty_modem_hup(info); return 0; } } @@ -491,13 +541,17 @@ static int isdn_status_callback(isdn_ctrl * c) /* Schedule CONNECT-Message to any tty, waiting for it and * set DCD-bit of its modem-status. */ - if (dev->mdm.info[mi].flags & + info = &dev->mdm.info[mi]; + if (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { - dev->mdm.msr[mi] |= UART_MSR_DCD; - if (dev->mdm.dialing[mi]) - dev->mdm.dialing[mi] = 0; - dev->mdm.rcvsched[mi] = 1; - isdn_tty_modem_result(5, &dev->mdm.info[mi]); + info->msr |= UART_MSR_DCD; + if (info->dialing) + info->dialing = 0; + info->rcvsched = 1; + if (USG_MODEM(dev->usage[i])) + isdn_tty_modem_result(5, info); + if (USG_VOICE(dev->usage[i])) + isdn_tty_modem_result(11, info); } } break; @@ -513,15 +567,16 @@ static int isdn_status_callback(isdn_ctrl * c) isdn_info_update(); if ((mi = dev->m_idx[i]) >= 0) { /* Signal hangup to tty-device, schedule NO CARRIER-message */ - if (dev->mdm.info[mi].flags & + info = &dev->mdm.info[mi]; + if (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { - dev->mdm.msr[mi] &= ~(UART_MSR_DCD | UART_MSR_RI); - if (dev->mdm.online[mi]) - isdn_tty_modem_result(3, &dev->mdm.info[mi]); + info->msr &= ~(UART_MSR_DCD | UART_MSR_RI); + if (info->online) + isdn_tty_modem_result(3, info); #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n"); #endif - isdn_tty_modem_hup(&dev->mdm.info[mi]); + isdn_tty_modem_hup(info); } } break; @@ -536,16 +591,17 @@ static int isdn_status_callback(isdn_ctrl * c) if (isdn_net_stat_callback(i, c->command)) break; if ((mi = dev->m_idx[i]) >= 0) { - if (dev->mdm.info[mi].flags & + info = &dev->mdm.info[mi]; + if (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { - if (dev->mdm.dialing[mi]) { - dev->mdm.dialing[mi] = 0; - isdn_tty_modem_result(6, &dev->mdm.info[mi]); + if (info->dialing) { + info->dialing = 0; + isdn_tty_modem_result(6, info); } - dev->mdm.msr[mi] &= ~UART_MSR_DCD; - if (dev->mdm.online[mi]) { - isdn_tty_modem_result(3, &dev->mdm.info[mi]); - dev->mdm.online[mi] = 0; + info->msr &= ~UART_MSR_DCD; + if (info->online) { + isdn_tty_modem_result(3, info); + info->online = 0; } } } @@ -569,6 +625,7 @@ static int isdn_status_callback(isdn_ctrl * c) kfree(dev->drv[di]->rcvcount); for (i = 0; i < dev->drv[di]->channels; i++) isdn_free_queue(&dev->drv[di]->rpqueue[i]); + kfree(dev->drv[di]->rpqueue); kfree(dev->drv[di]->rcv_waitq); kfree(dev->drv[di]->snd_waitq); kfree(dev->drv[di]); @@ -595,66 +652,109 @@ int isdn_getnum(char **p) return v; } +#define DLE 0x10 + +/* + * isdn_readbchan() tries to get data from the read-queue. + * It MUST be called with interrupts off. + */ int isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, int user) { - int avail; int left; int count; - int copy_l; + int count_pull; + int count_put; int dflag; - int flags; - pqueue *p; + struct sk_buff *skb; u_char *cp; - if (!dev->drv[di]->rpqueue[channel]) { + if (!dev->drv[di]) + return 0; + if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) { if (user) interruptible_sleep_on(&dev->drv[di]->rcv_waitq[channel]); else return 0; } - if (!dev->drv[di]) - return 0; - save_flags(flags); - cli(); - avail = dev->drv[di]->rcvcount[channel]; - restore_flags(flags); - left = MIN(len, avail); + left = MIN(len, dev->drv[di]->rcvcount[channel]); cp = buf; count = 0; while (left) { - if ((copy_l = dev->drv[di]->rpqueue[channel]->length) > left) { - copy_l = left; - dflag = 0; - } else - dflag = 1; - p = dev->drv[di]->rpqueue[channel]; - if (user) - memcpy_tofs(cp, p->rptr, copy_l); - else - memcpy(cp, p->rptr, copy_l); - if (fp) { - memset(fp, 0, copy_l); - fp += copy_l; - } - left -= copy_l; - count += copy_l; - cp += copy_l; - if (dflag) { + if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel]))) + break; + if (skb->lock) + break; + skb->lock = 1; + if (skb->users) { + /* users is the count of DLE's in + * this buff when in voice mode. + */ + char *p = skb->data; + unsigned long DLEmask = (1 << channel); + + dflag = 0; + count_pull = count_put = 0; + while ((count_pull < skb->len) && (left-- > 0)) { + if (dev->drv[di]->DLEflag & DLEmask) { + if (user) + put_fs_byte(DLE,cp++); + else + *cp++ = DLE; + dev->drv[di]->DLEflag &= ~DLEmask; + } else { + if (user) + put_fs_byte(*p,cp++); + else + *cp++ = *p; + if (*p == DLE) { + dev->drv[di]->DLEflag |= DLEmask; + skb->users--; + } + p++; + count_pull++; + } + count_put++; + } + if (count_pull >= skb->len) + dflag = 1; + } else { + /* No DLE's in buff, so simply copy it */ + dflag = 1; + if ((count_pull = skb->len) > left) { + count_pull = left; + dflag = 0; + } + count_put = count_pull; + if (user) + memcpy_tofs(cp, skb->data, count_put); + else + memcpy(cp, skb->data, count_put); + cp += count_put; + left -= count_put; + } + count += count_put; + if (fp) { + memset(fp, 0, count_put); + fp += count_put; + } + if (dflag) { + /* We got all the data in this buff. + * Now we can dequeue it. + */ if (fp) *(fp - 1) = 0xff; - save_flags(flags); - cli(); - dev->drv[di]->rpqueue[channel] = (pqueue *) p->next; - kfree_s(p, p->size); - restore_flags(flags); + skb->lock = 0; + skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]); + isdn_trash_skb(skb, FREE_READ); } else { - p->rptr += copy_l; - p->length -= copy_l; - } - save_flags(flags); - cli(); - dev->drv[di]->rcvcount[channel] -= copy_l; - restore_flags(flags); + /* Not yet emptied this buff, so it + * must stay in the queue, for further calls + * but we pull off the data we got until now. + */ + skb_pull(skb,count_pull); + skb->lock = 0; + } + dev->drv[di]->rcvcount[channel] -= count_put; } return count; } @@ -749,9 +849,7 @@ static int isdn_read(struct inode *inode, struct file *file, char *buf, int coun return -EAGAIN; interruptible_sleep_on(&(dev->info_waitq)); } - save_flags(flags); p = isdn_statstr(); - restore_flags(flags); file->private_data = 0; if ((len = strlen(p)) <= count) { memcpy_tofs(buf, p, len); @@ -769,8 +867,11 @@ static int isdn_read(struct inode *inode, struct file *file, char *buf, int coun if (!dev->drv[drvidx]->running) return -ENODEV; chidx = isdn_minor2chan(minor); + save_flags(flags); + cli(); len = isdn_readbchan(drvidx, chidx, buf, 0, count, 1); file->f_pos += len; + restore_flags(flags); return len; } if (minor <= ISDN_MINOR_CTRLMAX) { @@ -784,7 +885,8 @@ static int isdn_read(struct inode *inode, struct file *file, char *buf, int coun } if (dev->drv[drvidx]->interface->readstat) len = dev->drv[drvidx]->interface-> - readstat(buf, MIN(count, dev->drv[drvidx]->stavail), 1); + readstat(buf, MIN(count, dev->drv[drvidx]->stavail), + 1, drvidx, isdn_minor2chan(minor)); else len = 0; save_flags(flags); @@ -826,7 +928,6 @@ static int isdn_write(struct inode *inode, struct file *file, const char *buf, i if (!dev->drv[drvidx]->running) return -ENODEV; chidx = isdn_minor2chan(minor); - dev->obytes[minor] += count; while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count) interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]); return count; @@ -842,7 +943,8 @@ static int isdn_write(struct inode *inode, struct file *file, const char *buf, i return -ENODEV; */ if (dev->drv[drvidx]->interface->writecmd) - return (dev->drv[drvidx]->interface->writecmd(buf, count, 1)); + return (dev->drv[drvidx]->interface-> + writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor))); else return count; } @@ -856,6 +958,7 @@ static int isdn_write(struct inode *inode, struct file *file, const char *buf, i static int isdn_select(struct inode *inode, struct file *file, int type, select_table * st) { uint minor = MINOR(inode->i_rdev); + int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); if (minor == ISDN_MINOR_STATUS) { if (file->private_data) @@ -866,8 +969,18 @@ static int isdn_select(struct inode *inode, struct file *file, int type, select_ return 0; } } - if (minor <= ISDN_MINOR_CTRLMAX) + if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) { + if (drvidx < 0) + return -ENODEV; + if (dev->drv[drvidx]->stavail) + return 1; + else { + if (st) + select_wait(&(dev->drv[drvidx]->st_waitq), st); + return 0; + } return 1; + } #ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) return (isdn_ppp_select(minor - ISDN_MINOR_PPP, file, type, st)); @@ -1178,8 +1291,15 @@ static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong ar memcpy_fromfs(name,(char*)arg,sizeof(name)); return isdn_ppp_dial_slave(name); case IIOCNETDLN: - /* remove one link from bundle; removed for i4l 0.7.1 */ - return 2; + if(arg) { + if ((ret = verify_area(VERIFY_READ, + (void*)arg, + sizeof(name)))) + return ret; + } else + return -EINVAL; + memcpy_fromfs(name,(char*)arg,sizeof(name)); + return isdn_ppp_hangup_slave(name); #endif case IIOCNETHUP: /* Force hangup of a network-interface */ @@ -1212,7 +1332,8 @@ static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong ar if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(isdn_ioctl_struct)))) return ret; - memcpy_fromfs((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)); + memcpy_fromfs((char *) &iocts, (char *) arg, + sizeof(isdn_ioctl_struct)); if (strlen(iocts.drvid)) { if ((p = strchr(iocts.drvid, ','))) *p = 0; @@ -1260,9 +1381,10 @@ static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong ar return ret; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - memcpy_tofs(p, dev->mdm.atmodem[i].profile, ISDN_MODEM_ANZREG); + memcpy_tofs(p, dev->mdm.info[i].emu.profile, + ISDN_MODEM_ANZREG); p += ISDN_MODEM_ANZREG; - memcpy_tofs(p, dev->mdm.atmodem[i].pmsn, ISDN_MSNLEN); + memcpy_tofs(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN); p += ISDN_MSNLEN; } return (ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS; @@ -1281,9 +1403,10 @@ static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong ar return ret; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - memcpy_fromfs(dev->mdm.atmodem[i].profile, p, ISDN_MODEM_ANZREG); + memcpy_fromfs(dev->mdm.info[i].emu.profile, p, + ISDN_MODEM_ANZREG); p += ISDN_MODEM_ANZREG; - memcpy_fromfs(dev->mdm.atmodem[i].pmsn, p, ISDN_MSNLEN); + memcpy_fromfs(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN); p += ISDN_MSNLEN; } return 0; @@ -1410,6 +1533,7 @@ static int isdn_open(struct inode *ino, struct file *filep) if (minor == ISDN_MINOR_STATUS) { infostruct *p; + if ((p = (infostruct *) kmalloc(sizeof(infostruct), GFP_KERNEL))) { MOD_INC_USE_COUNT; p->next = (char *) dev->infochain; @@ -1605,7 +1729,8 @@ void isdn_free_channel(int di, int ch, int usage) dev->ibytes[i] = 0; dev->obytes[i] = 0; isdn_info_update(); - restore_flags(flags); + isdn_free_queue(&dev->drv[di]->rpqueue[ch]); + restore_flags(flags); return; } restore_flags(flags); @@ -1633,54 +1758,62 @@ void isdn_unexclusive_channel(int di, int ch) } /* - * receive callback handler for drivers supporting sk_buff's. + * receive callback handler for drivers not supporting sk_buff's. + * Parameters: + * + * di = Driver-Index. + * channel = Number of B-Channel (0...) + * buf = pointer to packet-data + * len = Length of packet-data + * */ - -void isdn_receive_skb_callback(int drvidx, int chan, struct sk_buff *skb) +void isdn_receive_callback(int drvidx, int chan, u_char *buf, int len) { - int i, len; + struct sk_buff *skb; if (dev->global_flags & ISDN_GLOBAL_STOPPED) return; - if ((i = isdn_dc2minor(drvidx,chan))==-1) - return; - len = skb->len; - if (isdn_net_rcv_skb(i, skb) == 0) { - isdn_receive_callback(drvidx, chan, skb->data, skb->len); - skb->free = 1; - kfree_skb(skb, FREE_READ); - } else - /* Update statistics */ - dev->ibytes[i] += len; + skb = dev_alloc_skb(len); + if (skb) { + memcpy(skb_put(skb, len), buf, len); + isdn_receive_skb_callback(drvidx, chan, skb); + } else + printk(KERN_WARNING "isdn: rcv alloc_skb failed, packet dropped.\n"); } /* * writebuf replacement for SKB_ABLE drivers */ - int isdn_writebuf_stub(int drvidx, int chan, const u_char *buf, int len, int user) { + int ret; + if (dev->drv[drvidx]->interface->writebuf) - return dev->drv[drvidx]->interface->writebuf(drvidx, chan, buf, - len, user); + ret = dev->drv[drvidx]->interface->writebuf(drvidx, chan, buf, + len, user); else { - struct sk_buff * skb; + struct sk_buff * skb; - skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len, GFP_ATOMIC); - if (skb == NULL) - return 0; + skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len, + GFP_ATOMIC); + if (skb == NULL) + return 0; - skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen); - skb->free = 1; + skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen); + skb->free = 1; - if (user) - memcpy_fromfs(skb_put(skb, len), buf, len); - else - memcpy(skb_put(skb, len), buf, len); + if (user) + memcpy_fromfs(skb_put(skb, len), buf, len); + else + memcpy(skb_put(skb, len), buf, len); - return dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, skb); + ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, + chan, skb); } + if (ret > 0) + dev->obytes[isdn_dc2minor(drvidx,chan)] += ret; + return ret; } /* @@ -1703,6 +1836,8 @@ int isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff * skb) writebuf(drvidx,chan,skb->data,skb->len,0))==skb->len) dev_kfree_skb(skb, FREE_WRITE); } + if (ret > 0) + dev->obytes[isdn_dc2minor(drvidx,chan)] += skb->len; return ret; } @@ -1750,14 +1885,17 @@ int register_isdn(isdn_if * i) return 0; } memset((char *) d->rcvcount, 0, sizeof(int) * n); - if (!(d->rpqueue = (pqueue **) kmalloc(sizeof(pqueue *) * n, GFP_KERNEL))) { - printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n"); - kfree(d->rcvcount); - kfree(d->rcverr); - kfree(d); - return 0; - } - memset((char *) d->rpqueue, 0, sizeof(pqueue *) * n); + if (!(d->rpqueue = + (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * n, GFP_KERNEL))) { + printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n"); + kfree(d->rcvcount); + kfree(d->rcverr); + kfree(d); + return 0; + } + for (j = 0; j < n; j++) { + skb_queue_head_init(&d->rpqueue[j]); + } if (!(d->rcv_waitq = (struct wait_queue **) kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n"); @@ -1799,6 +1937,9 @@ int register_isdn(isdn_if * i) sprintf(i->id, "line%d", drvidx); save_flags(flags); cli(); + for (j = 0; j < drvidx; j++) + if (!strcmp(i->id,dev->drvid[j])) + sprintf(i->id, "line%d", drvidx); for (j = 0; j < n; j++) for (k = 0; k < ISDN_MAX_CHANNELS; k++) if (dev->chanmap[k] < 0) { @@ -1894,7 +2035,7 @@ int isdn_init(void) tty_unregister_driver(&dev->mdm.tty_modem); tty_unregister_driver(&dev->mdm.cua_modem); for (i = 0; i < ISDN_MAX_CHANNELS; i++) - kfree(dev->mdm.info[i].xmit_buf - 4); + kfree(dev->mdm.info[i].xmit_buf); unregister_chrdev(ISDN_MAJOR, "isdn"); kfree(dev); return -EIO; @@ -1904,11 +2045,11 @@ int isdn_init(void) if (!has_exported) isdn_export_syms(); - printk(KERN_NOTICE "ISDN subsystem Rev: %s/%s/%s/%s", - isdn_getrev(isdn_revision), - isdn_getrev(isdn_tty_revision), - isdn_getrev(isdn_net_revision), - isdn_getrev(isdn_ppp_revision)); + printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(isdn_revision)); + printk("%s/", isdn_getrev(isdn_tty_revision)); + printk("%s/", isdn_getrev(isdn_net_revision)); + printk("%s/", isdn_getrev(isdn_ppp_revision)); + printk("%s", isdn_getrev(isdn_audio_revision)); #ifdef MODULE printk(" loaded\n"); @@ -1949,8 +2090,10 @@ void cleanup_module(void) restore_flags(flags); return; } - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - kfree(dev->mdm.info[i].xmit_buf - 4); + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + isdn_tty_cleanup_xmit(&dev->mdm.info[i]); + kfree(dev->mdm.info[i].xmit_buf); + } if (unregister_chrdev(ISDN_MAJOR, "isdn") != 0) { printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n"); } else { diff --git a/drivers/isdn/isdn_common.h b/drivers/isdn/isdn_common.h index 87b3b849614e..cae4567cb6b9 100644 --- a/drivers/isdn/isdn_common.h +++ b/drivers/isdn/isdn_common.h @@ -38,7 +38,6 @@ #undef ISDN_DEBUG_AT #undef ISDN_DEBUG_NET_DUMP #undef ISDN_DEBUG_NET_DIAL -#undef ISDN_DEBUG_NET_BUILDHDR #undef ISDN_DEBUG_NET_ICALL /* Prototypes */ diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c index ba93884f6084..1e62f62f207d 100644 --- a/drivers/isdn/isdn_net.c +++ b/drivers/isdn/isdn_net.c @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.5 1996/04/20 16:28:38 fritz Exp $ +/* $Id: isdn_net.c,v 1.11 1996/05/18 01:36:59 fritz Exp $ * * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -21,6 +21,25 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.c,v $ + * Revision 1.11 1996/05/18 01:36:59 fritz + * Added spelling corrections and some minor changes + * to stay in sync with kernel. + * + * Revision 1.10 1996/05/17 03:49:01 fritz + * Some cleanup. + * + * Revision 1.9 1996/05/06 11:34:57 hipp + * fixed a few bugs + * + * Revision 1.8 1996/04/30 21:04:40 fritz + * Test commit + * + * Revision 1.7 1996/04/30 11:10:42 fritz + * Added Michael's ippp-bind patch. + * + * Revision 1.6 1996/04/30 09:34:35 fritz + * Removed compatibility-macros. + * * Revision 1.5 1996/04/20 16:28:38 fritz * Made more parameters of the dial statemachine user-configurable and * added hangup after dial for more reliability using callback. @@ -55,9 +74,7 @@ * */ -#ifndef STANDALONE #include -#endif #define __NO_VERSION__ #include #include @@ -79,7 +96,9 @@ static int isdn_net_wildmat(char *s, char *p); static int isdn_net_start_xmit(struct sk_buff *, struct device *); static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *); -char *isdn_net_revision = "$Revision: 1.5 $"; +extern void dev_purge_queues(struct device *dev); /* move this to net/core/dev.c */ + +char *isdn_net_revision = "$Revision: 1.11 $"; /* * Code for raw-networking over ISDN @@ -142,6 +161,32 @@ isdn_net_bind_channel(isdn_net_local * lp, int idx) restore_flags(flags); } +/* + * unbind a net-interface (resets interface after an error) + */ +static void +isdn_net_unbind_channel(isdn_net_local * lp) +{ + ulong flags; + + save_flags(flags); + cli(); + if (lp->first_skb) { + dev_kfree_skb(lp->first_skb,FREE_WRITE); + lp->first_skb = NULL; + } + dev_purge_queues(&lp->netdev->dev); + lp->dialstate = 0; + dev->rx_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL; + dev->st_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL; + isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET); + lp->flags &= ~ISDN_NET_CONNECTED; + lp->isdn_device = -1; + lp->isdn_channel = -1; + + restore_flags(flags); +} + /* * Perform auto-hangup and cps-calculation for net-interfaces. * @@ -232,6 +277,8 @@ isdn_net_stat_callback(int idx, int cmd) /* Either D-Channel-hangup or error during dialout */ if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) { lp->flags &= ~ISDN_NET_CONNECTED; + if(lp->first_skb) + dev_kfree_skb(lp->first_skb,FREE_WRITE); isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET); #ifdef CONFIG_ISDN_PPP @@ -541,6 +588,7 @@ isdn_net_hangup(struct device *d) dev_kfree_skb(lp->first_skb,FREE_WRITE); lp->first_skb = NULL; } + dev_purge_queues(d); if (lp->flags & ISDN_NET_CONNECTED) { printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name); lp->dialstate = 0; @@ -695,8 +743,10 @@ isdn_net_xmit(struct device *ndev, isdn_net_local *lp, struct sk_buff *skb) /* For the other encaps the header has already been built */ #ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - return (isdn_ppp_xmit(skb, ndev)); + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { + ndev->tbusy = ret = isdn_ppp_xmit(skb, ndev); + return ret; + } #endif /* Reset hangup-timeout */ lp->huptimer = 0; @@ -755,7 +805,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev) { isdn_net_local *lp = (isdn_net_local *) ndev->priv; - if (ndev->tbusy) { if (jiffies - ndev->trans_start < 20) return 1; @@ -795,6 +844,8 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev) "isdn_net_start_xmit: No channel for %s\n", ndev->name); restore_flags(flags); + /* we probably should drop the skb here and return 0 to omit + 'socket destroy delayed' messages */ return 1; } /* Log packet, which triggered dialing */ @@ -805,15 +856,18 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev) /* Connect interface with channel */ isdn_net_bind_channel(lp, chi); #ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { + /* no 'first_skb' handling for syncPPP */ if (isdn_ppp_bind(lp) < 0) { - lp->dialstate = 0; - isdn_free_channel(lp->isdn_device, - lp->isdn_channel, - ISDN_USAGE_NET); + lp->first_skb = skb; /* net_unbind will free skb */ + isdn_net_unbind_channel(lp); restore_flags(flags); - return 1; + return 0; /* STN (skb to nirvana) ;) */ } + isdn_net_dial(); /* Initiate dialing */ + restore_flags(flags); + return 1; /* let upper layer requeue skb packet */ + } #endif /* remember first skb to speed up arp * when using encap ETHER @@ -1630,9 +1684,7 @@ isdn_net_find_icall(int di, int ch, int idx, char *num) #ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) if (isdn_ppp_bind(lp) < 0) { - isdn_free_channel(p->local.isdn_device, p->local.isdn_channel, - ISDN_USAGE_NET); - lp->dialstate = 0; + isdn_net_unbind_channel(lp); restore_flags(flags); return 0; } @@ -1647,15 +1699,6 @@ isdn_net_find_icall(int di, int ch, int idx, char *num) } else { printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", lp->name, nr, eaz); -#if 0 -/* why is this a CONFIG_ISDN_PPP feature ??? */ -#ifdef CONFIG_ISDN_PPP - if (p->local.isdn_device != -1) { - isdn_free_channel(p->local.isdn_device, p->local.isdn_channel, - ISDN_USAGE_NET); - } -#endif -#endif /* if this interface is dialing, it does it probably on a different device, so free this device */ if ((p->local.dialstate == 4) || (p->local.dialstate == 12)) @@ -1669,6 +1712,7 @@ isdn_net_find_icall(int di, int ch, int idx, char *num) p->local.isdn_device = di; p->local.isdn_channel = ch; p->local.ppp_minor = -1; + p->local.pppbind = -1; p->local.flags |= ISDN_NET_CONNECTED; p->local.dialstate = 7; p->local.dtimer = 0; @@ -1679,9 +1723,7 @@ isdn_net_find_icall(int di, int ch, int idx, char *num) #ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) if (isdn_ppp_bind(lp) < 0) { - isdn_free_channel(p->local.isdn_device, p->local.isdn_channel, - ISDN_USAGE_NET); - lp->dialstate = 0; + isdn_net_unbind_channel(lp); restore_flags(flags); return 0; } @@ -1745,9 +1787,9 @@ int isdn_net_force_dial_lp(isdn_net_local * lp) #ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) if (isdn_ppp_bind(lp) < 0) { - lp->dialstate = 0; - isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET); - return 1; + isdn_net_unbind_channel(lp); + restore_flags(flags); + return -EAGAIN; } #endif /* Initiate dialing */ @@ -1841,6 +1883,7 @@ isdn_net_new(char *name, struct device *master) netdev->local.pre_channel = -1; netdev->local.exclusive = -1; netdev->local.ppp_minor = -1; + netdev->local.pppbind = -1; netdev->local.l2_proto = ISDN_PROTO_L2_X75I; netdev->local.l3_proto = ISDN_PROTO_L3_TRANS; netdev->local.slavedelay = 10 * HZ; @@ -1987,6 +2030,7 @@ int isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) p->local.cbdelay = cfg->cbdelay; p->local.dialmax = cfg->dialmax; p->local.slavedelay = cfg->slavedelay * HZ; + p->local.pppbind = cfg->pppbind; if (cfg->secure) p->local.flags |= ISDN_NET_SECURE; else @@ -2062,14 +2106,16 @@ int isdn_net_getcfg(isdn_net_ioctl_cfg * cfg) cfg->l3_proto = p->local.l3_proto; cfg->p_encap = p->local.p_encap; cfg->secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0; - cfg->callback = (p->local.flags & ISDN_NET_CALLBACK) ? 1 : 0; - cfg->callback = (p->local.flags & ISDN_NET_CBOUT) ? 2 : 0; + cfg->callback = 0; + if (p->local.flags & ISDN_NET_CALLBACK) + cfg->callback = (p->local.flags & ISDN_NET_CBOUT)?2:1; cfg->cbhup = (p->local.flags & ISDN_NET_CBHUP) ? 1 : 0; cfg->chargehup = (p->local.hupflags & 4) ? 1 : 0; cfg->ihup = (p->local.hupflags & 8) ? 1 : 0; cfg->cbdelay = p->local.cbdelay; cfg->dialmax = p->local.dialmax; cfg->slavedelay = p->local.slavedelay / HZ; + cfg->pppbind = p->local.pppbind; if (p->local.slave) strcpy(cfg->slave, ((isdn_net_local *) p->local.slave->priv)->name); else @@ -2287,7 +2333,7 @@ static int isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q) restore_flags(flags); #ifdef CONFIG_ISDN_PPP - isdn_ppp_free_mpqueue(p); + isdn_ppp_free_mpqueue(p); /* still necessary? */ #endif kfree(p); @@ -2342,6 +2388,26 @@ int isdn_net_rmall(void) return 0; } +/* + * helper function to flush device queues + * the better place would be net/core/dev.c + */ +void dev_purge_queues(struct device *dev) +{ + int i; + for(i=0;ibuffs[i]))) + if(skb->free) + kfree_skb(skb,FREE_WRITE); + } + +} + + + + + diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c index eab7e4612719..ad77c57159a6 100644 --- a/drivers/isdn/isdn_ppp.c +++ b/drivers/isdn/isdn_ppp.c @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.c,v 1.5 1996/04/20 16:32:32 fritz Exp $ +/* $Id: isdn_ppp.c,v 1.9 1996/05/18 01:37:01 fritz Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -19,6 +19,19 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.c,v $ + * Revision 1.9 1996/05/18 01:37:01 fritz + * Added spelling corrections and some minor changes + * to stay in sync with kernel. + * + * Revision 1.8 1996/05/06 11:34:55 hipp + * fixed a few bugs + * + * Revision 1.7 1996/04/30 11:07:42 fritz + * Added Michael's ippp-bind patch. + * + * Revision 1.6 1996/04/30 09:33:09 fritz + * Removed compatibility-macros. + * * Revision 1.5 1996/04/20 16:32:32 fritz * Changed ippp_table to an array of pointers, allocating each part * separately. @@ -43,9 +56,7 @@ /* TODO: right tbusy handling when using MP */ -#ifndef STANDALONE #include -#endif #define __NO_VERSION__ #include #include @@ -58,8 +69,8 @@ #endif /* Prototypes */ -static int isdn_ppp_fill_rq(char *buf, int len, int minor); -static int isdn_ppp_hangup(int); +static int isdn_ppp_fill_rq(char *buf, int len,int proto, int minor); +static int isdn_ppp_closewait(int); static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto); static int isdn_ppp_if_get_unit(char **namebuf); @@ -72,47 +83,53 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb, int BEbyte, int *sqno, int min_sqno); #endif -char *isdn_ppp_revision = "$Revision: 1.5 $"; +char *isdn_ppp_revision = "$Revision: 1.9 $"; struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; extern int isdn_net_force_dial_lp(isdn_net_local *); -int isdn_ppp_free(isdn_net_local * lp) +/* + * unbind isdn_net_local <=> ippp-device + * note: it can happen, that we hangup/free the master before the slaves + */ +int isdn_ppp_free(isdn_net_local *lp) { + isdn_net_local *master_lp=lp; + if (lp->ppp_minor < 0) return 0; #ifdef CONFIG_ISDN_MPP if(lp->master) - { - isdn_net_dev *p = dev->netdev; - lp->last->next = lp->next; - lp->next->last = lp->last; - if(lp->netdev->queue == lp) - lp->netdev->queue = lp->next; - lp->next = lp->last = lp; - while(p) { - if(lp == &p->local) { - lp->netdev = p; - break; - } - p=p->next; + master_lp = (isdn_net_local *) lp->master->priv; + + lp->last->next = lp->next; + lp->next->last = lp->last; + if(master_lp->netdev->queue == lp) { + master_lp->netdev->queue = lp->next; + if(lp->next == lp) { /* last link in queue? */ + master_lp->netdev->ib.bundled = 0; + isdn_ppp_free_mpqueue(master_lp->netdev); + isdn_ppp_free_sqqueue(master_lp->netdev); } - } else { - lp->netdev->ib.bundled = 0; - /* last link: free mpqueue, free sqqueue ? */ } - + lp->next = lp->last = lp; /* (re)set own pointers */ #endif - isdn_ppp_hangup(lp->ppp_minor); -#if 0 - printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_minor, (long) lp,(long) ippp_table[lp->ppp_minor]->lp); -#endif - ippp_table[lp->ppp_minor]->lp = NULL; + isdn_ppp_closewait(lp->ppp_minor); /* force wakeup on ippp device */ + + if(ippp_table[lp->ppp_minor]->debug & 0x1) + printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_minor, (long) lp,(long) ippp_table[lp->ppp_minor]->lp); + + ippp_table[lp->ppp_minor]->lp = NULL; /* link is down .. set lp to NULL */ + lp->ppp_minor = -1; /* is this OK ?? */ + return 0; } +/* + * bind isdn_net_local <=> ippp-device + */ int isdn_ppp_bind(isdn_net_local * lp) { int i; @@ -126,17 +143,32 @@ int isdn_ppp_bind(isdn_net_local * lp) save_flags(flags); cli(); - /* - * search a free device - */ - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (ippp_table[i]->state == IPPP_OPEN) { /* OPEN, but not connected! */ -#if 0 - printk(KERN_DEBUG "find_minor, %d lp: %08lx\n", i, (long) lp); -#endif - break; + if(lp->pppbind < 0) /* device bounded to ippp device ? */ + { + isdn_net_dev *net_dev = dev->netdev; + char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */ + memset(exclusive,0,ISDN_MAX_CHANNELS); + while (net_dev) { /* step through net devices to find exclusive minors */ + isdn_net_local *lp = &net_dev->local; + if(lp->pppbind >= 0) + exclusive[lp->pppbind] = 1; + net_dev = net_dev->next; + } + /* + * search a free device + */ + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + if (ippp_table[i]->state == IPPP_OPEN && !exclusive[i]) { /* OPEN, but not connected! */ + break; + } } } + else { + if (ippp_table[lp->pppbind]->state == IPPP_OPEN) /* OPEN, but not connected! */ + i = lp->pppbind; + else + i = ISDN_MAX_CHANNELS; /* trigger error */ + } if (i >= ISDN_MAX_CHANNELS) { restore_flags(flags); @@ -163,7 +195,12 @@ int isdn_ppp_bind(isdn_net_local * lp) return lp->ppp_minor; } -static int isdn_ppp_hangup(int minor) +/* + * there was a hangup on the netdevice + * force wakeup of the ippp device + * go into 'device waits for release' state + */ +static int isdn_ppp_closewait(int minor) { if (minor < 0 || minor >= ISDN_MAX_CHANNELS) return 0; @@ -181,9 +218,8 @@ static int isdn_ppp_hangup(int minor) int isdn_ppp_open(int minor, struct file *file) { -#if 0 - printk(KERN_DEBUG "ippp, open, minor: %d state: %04x\n", minor,ippp_table[minor]->state); -#endif + if(ippp_table[minor]->debug & 0x1) + printk(KERN_DEBUG "ippp, open, minor: %d state: %04x\n", minor,ippp_table[minor]->state); if (ippp_table[minor]->state) return -EBUSY; @@ -219,6 +255,9 @@ int isdn_ppp_open(int minor, struct file *file) return 0; } +/* + * release ippp device + */ void isdn_ppp_release(int minor, struct file *file) { int i; @@ -226,29 +265,24 @@ void isdn_ppp_release(int minor, struct file *file) if (minor < 0 || minor >= ISDN_MAX_CHANNELS) return; -#if 0 - printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", minor, (long) ippp_table[minor]->lp); -#endif + if(ippp_table[minor]->debug & 0x1) + printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", minor, (long) ippp_table[minor]->lp); if (ippp_table[minor]->lp) { /* a lp address says: this link is still up */ isdn_net_dev *p = dev->netdev; - while(p) { /* find interface for our lp; */ - if(&p->local == ippp_table[minor]->lp) - break; - p = p->next; - } - if(!p) { - printk(KERN_ERR "isdn_ppp_release: Can't find device for net_local\n"); - p = ippp_table[minor]->lp->netdev; - } + p = ippp_table[minor]->lp->netdev; ippp_table[minor]->lp->ppp_minor = -1; - isdn_net_hangup(&p->dev); /* lp->ppp_minor==-1 => no calling of isdn_ppp_hangup() */ + isdn_net_hangup(&p->dev); /* lp->ppp_minor==-1 => no calling of isdn_ppp_closewait() */ ippp_table[minor]->lp = NULL; } for (i = 0; i < NUM_RCV_BUFFS; i++) { - if (ippp_table[minor]->rq[i].buf) + if (ippp_table[minor]->rq[i].buf) { kfree(ippp_table[minor]->rq[i].buf); + ippp_table[minor]->rq[i].buf = NULL; + } } + ippp_table[minor]->first = ippp_table[minor]->rq + NUM_RCV_BUFFS - 1; /* receive queue */ + ippp_table[minor]->last = ippp_table[minor]->rq; #ifdef CONFIG_ISDN_PPP_VJ slhc_free(ippp_table[minor]->slcomp); @@ -258,6 +292,9 @@ void isdn_ppp_release(int minor, struct file *file) ippp_table[minor]->state = 0; } +/* + * get_arg .. ioctl helper + */ static int get_arg(void *b, unsigned long *val) { int r; @@ -267,6 +304,9 @@ static int get_arg(void *b, unsigned long *val) return 0; } +/* + * set arg .. ioctl helper + */ static int set_arg(void *b, unsigned long val) { int r; @@ -276,15 +316,17 @@ static int set_arg(void *b, unsigned long val) return 0; } +/* + * ippp device ioctl + */ int isdn_ppp_ioctl(int minor, struct file *file, unsigned int cmd, unsigned long arg) { unsigned long val; int r; -#if 0 - printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x",minor,cmd); - printk(KERN_DEBUG " state: %x\n",ippp_table[minor]->state); -#endif + if(ippp_table[minor]->debug & 0x1) + printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", + minor,cmd,ippp_table[minor]->state); if (!(ippp_table[minor]->state & IPPP_OPEN)) return -EINVAL; @@ -328,8 +370,9 @@ int isdn_ppp_ioctl(int minor, struct file *file, unsigned int cmd, unsigned long return r; } if (val & SC_ENABLE_IP && !(ippp_table[minor]->pppcfg & SC_ENABLE_IP)) { - ippp_table[minor]->lp->netdev->dev.tbusy = 0; - mark_bh(NET_BH); /* OK .. we are ready to send the first buffer */ + isdn_net_local *lp = ippp_table[minor]->lp; + lp->netdev->dev.tbusy = 0; + mark_bh(NET_BH); /* OK .. we are ready to send buffers */ } ippp_table[minor]->pppcfg = val; break; @@ -354,8 +397,13 @@ int isdn_ppp_ioctl(int minor, struct file *file, unsigned int cmd, unsigned long ippp_table[minor]->maxcid = val; break; case PPPIOCGDEBUG: + if ((r = set_arg((void *) arg, ippp_table[minor]->debug))) + return r; break; case PPPIOCSDEBUG: + if ((r = get_arg((void *) arg, &val))) + return r; + ippp_table[minor]->debug = val; break; default: break; @@ -368,9 +416,8 @@ int isdn_ppp_select(int minor, struct file *file, int type, select_table * st) struct ippp_buf_queue *bf, *bl; unsigned long flags; -#if 0 - printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n",minor,type); -#endif + if(ippp_table[minor]->debug & 0x2) + printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n",minor,type); if (!(ippp_table[minor]->state & IPPP_OPEN)) return -EINVAL; @@ -381,6 +428,9 @@ int isdn_ppp_select(int minor, struct file *file, int type, select_table * st) cli(); bl = ippp_table[minor]->last; bf = ippp_table[minor]->first; + /* + * if IPPP_NOBLOCK is set we return even if we have nothing to read + */ if (bf->next == bl && !(ippp_table[minor]->state & IPPP_NOBLOCK)) { select_wait(&ippp_table[minor]->wq, st); restore_flags(flags); @@ -403,7 +453,7 @@ int isdn_ppp_select(int minor, struct file *file, int type, select_table * st) * fill up isdn_ppp_read() queue .. */ -static int isdn_ppp_fill_rq(char *buf, int len, int minor) +static int isdn_ppp_fill_rq(char *buf, int len,int proto, int minor) { struct ippp_buf_queue *bf, *bl; unsigned long flags; @@ -428,15 +478,19 @@ static int isdn_ppp_fill_rq(char *buf, int len, int minor) kfree(bf->buf); ippp_table[minor]->first = bf; } - bl->buf = (char *) kmalloc(len, GFP_ATOMIC); + bl->buf = (char *) kmalloc(len+4, GFP_ATOMIC); if (!bl->buf) { printk(KERN_WARNING "ippp: Can't alloc buf\n"); restore_flags(flags); return 0; } - bl->len = len; + bl->len = len+4; - memcpy(bl->buf, buf, len); + bl->buf[0] = PPP_ALLSTATIONS; + bl->buf[1] = PPP_UI; + bl->buf[2] = proto >> 8; + bl->buf[3] = proto & 0xff; + memcpy(bl->buf+4, buf, len); ippp_table[minor]->last = bl->next; restore_flags(flags); @@ -502,6 +556,7 @@ int isdn_ppp_write(int minor, struct file *file, const char *buf, int count) if (!lp) printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n"); else { + lp->huptimer = 0; if (lp->isdn_device < 0 || lp->isdn_channel < 0) return 0; @@ -526,11 +581,11 @@ int isdn_ppp_init(void) if (!(ippp_table[i] = (struct ippp_struct *) kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) { printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n"); - for (j = 0; j < i; j++) - kfree(ippp_table[i]); + for (j = 0; j < i; j++) + kfree(ippp_table[i]); return -1; } - memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct)); + memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct)); ippp_table[i]->state = 0; ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1; ippp_table[i]->last = ippp_table[i]->rq; @@ -559,14 +614,15 @@ void isdn_ppp_cleanup(void) void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb) { -#if 0 - printk(KERN_DEBUG "recv, skb %d\n",skb->len); -#endif + if(ippp_table[lp->ppp_minor]->debug & 0x4) + printk(KERN_DEBUG "recv skb, len: %ld\n",skb->len); if(skb->data[0] == 0xff && skb->data[1] == 0x03) skb_pull(skb,2); - else if (ippp_table[lp->ppp_minor]->pppcfg & SC_REJ_COMP_AC) + else if (ippp_table[lp->ppp_minor]->pppcfg & SC_REJ_COMP_AC) { + dev_kfree_skb(skb,FREE_WRITE); return; /* discard it silently */ + } #ifdef CONFIG_ISDN_MPP if (!(ippp_table[lp->ppp_minor]->mpppcfg & SC_REJ_MP_PROT)) { @@ -583,11 +639,10 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf isdn_net_local *lpq; int sqno, min_sqno, tseq; u_char BEbyte = skb->data[0]; -#if 0 - printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_minor, proto , - (int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2], - (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]); -#endif + if(ippp_table[lp->ppp_minor]->debug & 0x8) + printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_minor, proto , + (int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2], + (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]); if (!(ippp_table[lp->ppp_minor]->mpppcfg & SC_IN_SHORT_SEQ)) { sqno = ((int) skb->data[1] << 16) + ((int) skb->data[2] << 8) + (int) skb->data[3]; skb_pull(skb,4); @@ -657,8 +712,9 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf q = (struct sqqueue *) kmalloc(sizeof(struct sqqueue), GFP_ATOMIC); if (!q) { - printk(KERN_WARNING "ippp: err, no memory !!\n"); net_dev->ib.modify = 0; + printk(KERN_WARNING "ippp/MPPP: Bad! Can't alloc sq node!\n"); + dev_kfree_skb(skb,FREE_WRITE); return; /* discard */ } q->skb = skb; @@ -726,9 +782,8 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru } } -#if 0 - printk(KERN_DEBUG "push, skb %d %04x\n",skb->len,proto); -#endif + if(ippp_table[lp->ppp_minor]->debug & 0x10) + printk(KERN_DEBUG "push, skb %ld %04x\n",skb->len,proto); switch (proto) { case PPP_IPX: /* untested */ @@ -755,6 +810,7 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru if (!skb) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); net_dev->local.stats.rx_dropped++; + dev_kfree_skb(skb_old,FREE_WRITE); return; } skb->dev = dev; @@ -770,16 +826,12 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru #else printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n"); lp->stats.rx_dropped++; + dev_kfree_skb(skb,FREE_WRITE); return; #endif break; default: - skb_push(skb,4); - skb->data[0] = 0xff; - skb->data[1] = 0x03; - skb->data[2] = (proto>>8); - skb->data[3] = proto & 0xff; - isdn_ppp_fill_rq(skb->data, skb->len, lp->ppp_minor); /* push data to pppd device */ + isdn_ppp_fill_rq(skb->data, skb->len,proto, lp->ppp_minor); /* push data to pppd device */ dev_kfree_skb(skb,FREE_WRITE); return; } @@ -793,19 +845,32 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru } /* - * send ppp frame .. we expect a PIDCOMPable proto -- + * send ppp frame .. we expect a PIDCOMPressable proto -- * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP) */ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) { - isdn_net_dev *nd = ((isdn_net_local *) dev->priv)->netdev; - isdn_net_local *lp = nd->queue; + struct device *mdev = ((isdn_net_local *) (dev->priv) )->master; /* get master (for redundancy) */ + isdn_net_local *lp,*mlp; + isdn_net_dev *nd; int proto = PPP_IP; /* 0x21 */ - struct ippp_struct *ipt = ippp_table[lp->ppp_minor]; -#if defined(CONFIG_ISDN_PPP_VJ) || defined(CONFIG_ISDN_MPP) - struct ippp_struct *ipts = ippp_table[lp->netdev->local.ppp_minor]; -#endif + struct ippp_struct *ipt,*ipts; + if(mdev) + mlp = (isdn_net_local *) (mdev->priv); + else + mlp = (isdn_net_local *) (dev->priv); + nd = mlp->netdev; /* get master lp */ + lp = nd->queue; /* get lp on top of queue */ + ipt = ippp_table[lp->ppp_minor]; + ipts = ippp_table[mlp->ppp_minor]; + + if (!(ipt->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ + printk(KERN_INFO "isdn, xmit: Packet blocked: %d %d\n", lp->isdn_device, lp->isdn_channel); + return 1; + } + lp->huptimer = 0; + /* If packet is to be resent, it has already been processed and * therefore its first bytes are already initialized. In this case * send it immediately ... @@ -817,17 +882,16 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) /* future: step to next 'lp' when this lp is 'tbusy' */ -#if 0 - printk(KERN_DEBUG "xmit, skb %d\n",skb->len); -#endif + if(ippp_table[lp->ppp_minor]->debug & 0x4) + printk(KERN_DEBUG "xmit skb, len %ld\n",skb->len); #ifdef CONFIG_ISDN_PPP_VJ - if (ipt->pppcfg & SC_COMP_TCP) { + if (ipt->pppcfg & SC_COMP_TCP) { /* ipt or ipts ? -> check this again! */ u_char *buf = skb->data; int pktlen; int len = 4; #ifdef CONFIG_ISDN_MPP - if (ipt->mpppcfg & SC_MP_PROT) /* sigh */ + if (ipt->mpppcfg & SC_MP_PROT) /* sigh */ /* ipt or ipts ?? */ if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) len += 3; else @@ -851,9 +915,8 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) } #endif -#if 0 - printk(KERN_DEBUG "xmit, skb %d %04x\n",skb->len,proto); -#endif + if(ippp_table[lp->ppp_minor]->debug & 0x24) + printk(KERN_DEBUG "xmit2 skb, len %ld, proto %04x\n",skb->len,proto); #ifdef CONFIG_ISDN_MPP if (ipt->mpppcfg & SC_MP_PROT) { @@ -883,15 +946,25 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) skb->data[2] = proto >> 8; skb->data[3] = proto & 0xff; - lp->huptimer = 0; - if (!(ipt->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ - printk(KERN_INFO "isdn, xmit: Packet blocked: %d %d\n", lp->isdn_device, lp->isdn_channel); - return 1; - } /* tx-stats are now updated via BSENT-callback */ return (isdn_net_send_skb(dev , lp , skb)); } +void isdn_ppp_free_sqqueue(isdn_net_dev * p) +{ + struct sqqueue *q = p->ib.sq; + + p->ib.sq = NULL; + while(q) { + struct sqqueue *qn = q->next; + if(q->skb) + dev_kfree_skb(q->skb,FREE_WRITE); + kfree(q); + q = qn; + } + +} + void isdn_ppp_free_mpqueue(isdn_net_dev * p) { struct mpqueue *ql, *q = p->mp_last; @@ -932,8 +1005,6 @@ static int isdn_ppp_bundle(int minor, int unit) nlp->next = lp; p->queue = nlp; - nlp->netdev = lp->netdev; - ippp_table[nlp->ppp_minor]->unit = ippp_table[lp->ppp_minor]->unit; /* maybe also SC_CCP stuff */ ippp_table[nlp->ppp_minor]->pppcfg |= ippp_table[lp->ppp_minor]->pppcfg & @@ -1239,4 +1310,34 @@ int isdn_ppp_dial_slave(char *name) #endif } +int isdn_ppp_hangup_slave(char *name) +{ +#ifdef CONFIG_ISDN_MPP + isdn_net_dev *ndev; + isdn_net_local *lp; + struct device *sdev; + + if(!(ndev = isdn_net_findif(name))) + return 1; + lp = &ndev->local; + if(!(lp->flags & ISDN_NET_CONNECTED)) + return 5; + + sdev = lp->slave; + while(sdev) + { + isdn_net_local *mlp = (isdn_net_local *) sdev->priv; + if((mlp->flags & ISDN_NET_CONNECTED)) + break; + sdev = mlp->slave; + } + if(!sdev) + return 2; + + isdn_net_hangup(sdev); + return 0; +#else + return -1; +#endif +} diff --git a/drivers/isdn/isdn_ppp.h b/drivers/isdn/isdn_ppp.h index 05a8036895d6..cb01128c33dd 100644 --- a/drivers/isdn/isdn_ppp.h +++ b/drivers/isdn/isdn_ppp.h @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.h,v 1.2 1996/04/20 16:35:11 fritz Exp $ +/* $Id: isdn_ppp.h,v 1.4 1996/05/06 11:34:56 hipp Exp $ * * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -19,6 +19,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.h,v $ + * Revision 1.4 1996/05/06 11:34:56 hipp + * fixed a few bugs + * + * Revision 1.3 1996/04/30 09:33:10 fritz + * Removed compatibility-macros. + * * Revision 1.2 1996/04/20 16:35:11 fritz * Changed isdn_ppp_receive to use sk_buff as parameter. * Added definition of isdn_ppp_dial_slave and ippp_table. @@ -40,6 +46,7 @@ extern int isdn_ppp_xmit(struct sk_buff *, struct device *); extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *); extern int isdn_ppp_dev_ioctl(struct device *, struct ifreq *, int); extern void isdn_ppp_free_mpqueue(isdn_net_dev *); +extern void isdn_ppp_free_sqqueue(isdn_net_dev *); extern int isdn_ppp_select(int, struct file *, int, select_table *); extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long); extern void isdn_ppp_release(int, struct file *); diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c index efa95c3562da..f76dcaf0923a 100644 --- a/drivers/isdn/isdn_tty.c +++ b/drivers/isdn/isdn_tty.c @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.4 1996/04/20 16:39:54 fritz Exp $ +/* $Id: isdn_tty.c,v 1.11 1996/05/18 01:37:03 fritz Exp $ * * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -20,6 +20,35 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.c,v $ + * Revision 1.11 1996/05/18 01:37:03 fritz + * Added spelling corrections and some minor changes + * to stay in sync with kernel. + * + * Revision 1.10 1996/05/17 03:51:49 fritz + * Changed DLE handling for audio receive. + * + * Revision 1.9 1996/05/11 21:52:07 fritz + * Changed queue management to use sk_buffs. + * + * Revision 1.8 1996/05/10 08:49:43 fritz + * Checkin before major changes of tty-code. + * + * Revision 1.7 1996/05/07 09:15:09 fritz + * Reorganized and general cleanup. + * Bugfixes: + * - Audio-transmit working now. + * - "NO CARRIER" now reported, when hanging up with DTR low. + * - Corrected CTS handling. + * + * Revision 1.6 1996/05/02 03:59:25 fritz + * Bugfixes: + * - On dialout, layer-2 setup had been incomplete + * when using new auto-layer2 feature. + * - On hangup, "NO CARRIER" message sometimes missing. + * + * Revision 1.5 1996/04/30 21:05:25 fritz + * Test commit + * * Revision 1.4 1996/04/20 16:39:54 fritz * Changed all io to go through generic routines in isdn_common.c * Fixed a real ugly bug in modem-emulator: 'ATA' had been accepted @@ -39,14 +68,22 @@ #define __NO_VERSION__ #include #include +#include #include "isdn_common.h" #include "isdn_tty.h" +#ifdef CONFIG_ISDN_AUDIO +#include "isdn_audio.h" +#define VBUF 0x300 +#define VBUFX (VBUF/16) +#endif /* Prototypes */ static int isdn_tty_edit_at(const char *, int, modem_info *, int); static void isdn_tty_check_esc(const u_char *, u_char, int, int *, int *, int); static void isdn_tty_modem_reset_regs(atemu *, int); +static void isdn_tty_cmd_ATA(modem_info *); +static void isdn_tty_at_cout(char *, modem_info *); /* Leave this unchanged unless you know what you do! */ #define MODEM_PARANOIA_CHECK @@ -54,31 +91,53 @@ static void isdn_tty_modem_reset_regs(atemu *, int); static char *isdn_ttyname_ttyI = "ttyI"; static char *isdn_ttyname_cui = "cui"; -char *isdn_tty_revision = "$Revision: 1.4 $"; - -int isdn_tty_try_read(int i, u_char * buf, int len) +static int bit2si[8] = {1,5,7,7,7,7,7,7}; +static int si2bit[8] = {4,1,4,4,4,4,4,4}; + +char *isdn_tty_revision = "$Revision: 1.11 $"; + +/* isdn_tty_try_read() is called from within isdn_receive_callback() + * to stuff incoming data directly into a tty's flip-buffer. This + * is done to speed up tty-receiving if the receive-queue is empty. + * This routine MUST be called with interrupts off. + * Return: + * 1 = Success + * 0 = Failure, data has to be bufferd and later processed by + * isdn_tty_readmodem(). + */ +#define DLE 0x10 +#define ETX 0x03 +int isdn_tty_try_read(modem_info *info, struct sk_buff *skb) { int c; + int len; struct tty_struct *tty; - if (i < 0) - return 0; - if (dev->mdm.online[i]) { - if ((tty = dev->mdm.info[i].tty)) { - if (dev->mdm.info[i].MCR & UART_MCR_RTS) { - c = TTY_FLIPBUF_SIZE - tty->flip.count - 1; + if (info->online) { + if ((tty = info->tty)) { + if (info->mcr & UART_MCR_RTS) { + c = TTY_FLIPBUF_SIZE - tty->flip.count; + len = skb->len + skb->users; if (c >= len) { - if (len > 1) { - memcpy(tty->flip.char_buf_ptr, buf, len); - tty->flip.count += len; - memset(tty->flip.flag_buf_ptr, 0, len); - if (dev->mdm.atmodem[i].mdmreg[12] & 128) - tty->flip.flag_buf_ptr[len - 1] = 0xff; - tty->flip.flag_buf_ptr += len; - tty->flip.char_buf_ptr += len; - } else - tty_insert_flip_char(tty, buf[0], 0); + if (skb->users) + while (skb->len--) { + if (*skb->data == DLE) + tty_insert_flip_char(tty, DLE, 0); + tty_insert_flip_char(tty, *skb->data++, 0); + } + else { + memcpy(tty->flip.char_buf_ptr, + skb->data, len); + tty->flip.count += len; + tty->flip.char_buf_ptr += len; + memset(tty->flip.flag_buf_ptr, 0, len); + tty->flip.flag_buf_ptr += len; + } + if (info->emu.mdmreg[12] & 128) + tty->flip.flag_buf_ptr[len - 1] = 0xff; queue_task_irq_off(&tty->flip.tqueue, &tq_timer); + skb->free = 1; + kfree_skb(skb, FREE_READ); return 1; } } @@ -87,6 +146,10 @@ int isdn_tty_try_read(int i, u_char * buf, int len) return 0; } +/* isdn_tty_readmodem() is called periodically from within timer-interrupt. + * It tries getting received data from the receive queue an stuff it into + * the tty's flip-buffer. + */ void isdn_tty_readmodem(void) { int resched = 0; @@ -99,43 +162,140 @@ void isdn_tty_readmodem(void) modem_info *info; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if ((midx = dev->m_idx[i]) >= 0) - if (dev->mdm.online[midx]) { - save_flags(flags); - cli(); + if ((midx = dev->m_idx[i]) >= 0) { + info = &dev->mdm.info[midx]; + if (info->online) { r = 0; - info = &dev->mdm.info[midx]; if ((tty = info->tty)) { - if (info->MCR & UART_MCR_RTS) { - c = TTY_FLIPBUF_SIZE - tty->flip.count - 1; + if (info->mcr & UART_MCR_RTS) { + c = TTY_FLIPBUF_SIZE - tty->flip.count; if (c > 0) { + save_flags(flags); + cli(); r = isdn_readbchan(info->isdn_driver, info->isdn_channel, tty->flip.char_buf_ptr, tty->flip.flag_buf_ptr, c, 0); - if (!(dev->mdm.atmodem[midx].mdmreg[12] & 128)) + /* CISCO AsyncPPP Hack */ + if (!(info->emu.mdmreg[12] & 128)) memset(tty->flip.flag_buf_ptr, 0, r); tty->flip.count += r; tty->flip.flag_buf_ptr += r; tty->flip.char_buf_ptr += r; if (r) queue_task_irq_off(&tty->flip.tqueue, &tq_timer); + restore_flags(flags); } } else r = 1; } else r = 1; - restore_flags(flags); if (r) { - dev->mdm.rcvsched[midx] = 0; + info->rcvsched = 0; resched = 1; } else - dev->mdm.rcvsched[midx] = 1; + info->rcvsched = 1; } + } } if (!resched) isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0); } +void isdn_tty_cleanup_xmit(modem_info *info) +{ + struct sk_buff *skb; + unsigned long flags; + + save_flags(flags); + cli(); + if (info->xmit_buf->qlen) + while ((skb = skb_dequeue(info->xmit_buf))) { + skb->free = 1; + kfree_skb(skb,FREE_WRITE); + } + restore_flags(flags); +} + +/* isdn_tty_senddown() is called either directly from within isdn_tty_write() + * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls + * outgoing data from the tty's xmit-buffer, handles voice-decompression or + * T.70 if necessary, and finally sends it out via isdn_writebuf_stub. + */ +static void isdn_tty_senddown(modem_info * info) +{ + struct tty_struct *tty = info->tty; + struct sk_buff *skb = skb_dequeue(info->xmit_buf); + + if (!skb) + return; + if (skb->free > 1) { + /* Post processing only once, if skb->free > 1 */ +#ifdef CONFIG_ISDN_AUDIO + if (info->vonline==2) { + char *ptr = skb->data; + int len = skb->len; + + /* For now, ifmt is fixed to 1 (alaw), since this + * is used with ISDN everywhere in the world, except + * US, Canadia and Japan. + * Later, when US-ISDN protocols are implemented, + * this setting will depend on the D-channel protocol. + */ + int ifmt = 1; + /* voice conversion/decompression */ + switch (info->emu.vpar[3]) { + case 4: + skb_put(skb, len); + /* fall through */ + case 3: + skb_put(skb, len); + /* fall through */ + case 2: + skb_put(skb, len * 2); + /* adpcm, compatible to ZyXel 1496 modem + * with ROM revision 6.01 + */ + skb_pull(skb, len); + skb_trim(skb, isdn_audio_adpcm2xlaw(info->adpcms, + ifmt, + ptr, + skb->data, + len)); + break; + case 5: + /* a-law */ + if (!ifmt) + isdn_audio_alaw2ulaw(ptr,len); + break; + case 6: + /* u-law */ + if (ifmt) + isdn_audio_ulaw2alaw(ptr,len); + break; + } + } +#endif /* CONFIG_ISDN_AUDIO */ + if (info->emu.mdmreg[13] & 2) + /* Add T.70 simplified header */ + memcpy(skb_push(skb,4), "\1\0\1\0", 4); + /* Mark skb post-processed */ + skb->free = 1; + } + if (isdn_writebuf_skb_stub(info->isdn_driver, info->isdn_channel, + skb) > 0) { + if (skb_queue_empty(info->xmit_buf)) + info->xmit_count = 0; + if ((info->send_outstanding++) > 10) + info->msr &= ~UART_MSR_CTS; + info->lsr |= UART_LSR_TEMT; + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); + wake_up_interruptible(&tty->write_wait); + } else + skb_queue_head(info->xmit_buf,skb); +} + /************************************************************ * * Modem-functions @@ -144,78 +304,149 @@ void isdn_tty_readmodem(void) * ************************************************************/ +/* The nex routine is called once from within timer-interrupt + * triggered within isdn_tty_modem_ncarrier(). It calls + * isdn_tty_modem_result() to stuff a "NO CARRIER" Message + * into the tty's flip-buffer. + */ +static void isdn_tty_modem_do_ncarrier(unsigned long data) +{ + modem_info * info = (modem_info *)data; + isdn_tty_modem_result(3, info); +} + +/* Next routine is called, whenever the DTR-signal is raised. + * It checks the ncarrier-flag, and triggers the above routine + * when necessary. The ncarrier-flag is set, whenever DTR goes + * low. + */ +static void isdn_tty_modem_ncarrier(modem_info * info) +{ + if (info->ncarrier) { + info->ncarrier = 0; + info->nc_timer.expires = jiffies + HZ; + info->nc_timer.function = isdn_tty_modem_do_ncarrier; + info->nc_timer.data = (unsigned long)info; + add_timer(&info->nc_timer); + } +} + +/* isdn_tty_dial() performs dialing of a tty an the necessary + * setup of the lower levels befor that. + */ static void isdn_tty_dial(char *n, modem_info * info, atemu * m) { + int usg = ISDN_USAGE_MODEM; + int si = 7; + int l2 = m->mdmreg[14]; isdn_ctrl cmd; ulong flags; int i; - + int j; + + for (j=7;j>=0;j--) + if (m->mdmreg[18] & (1<mdmreg[20] = si2bit[si]; save_flags(flags); cli(); - i = isdn_get_free_channel(ISDN_USAGE_MODEM, m->mdmreg[14], m->mdmreg[15], -1, -1); + i = isdn_get_free_channel(usg, l2, m->mdmreg[15], -1, -1); if (i < 0) { restore_flags(flags); isdn_tty_modem_result(6, info); } else { - if (strlen(m->msn)) { - info->isdn_driver = dev->drvmap[i]; - info->isdn_channel = dev->chanmap[i]; - info->drv_index = i; - dev->m_idx[i] = info->line; - dev->usage[i] |= ISDN_USAGE_OUTGOING; - isdn_info_update(); - restore_flags(flags); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_CLREAZ; - dev->drv[info->isdn_driver]->interface->command(&cmd); - strcpy(cmd.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETEAZ; - dev->drv[info->isdn_driver]->interface->command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL2; - cmd.arg = info->isdn_channel + (m->mdmreg[14] << 8); - dev->drv[info->isdn_driver]->interface->command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8); - dev->drv[info->isdn_driver]->interface->command(&cmd); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - sprintf(cmd.num, "%s,%s,%d,%d", n, isdn_map_eaz2msn(m->msn, info->isdn_driver), - m->mdmreg[18], m->mdmreg[19]); - cmd.command = ISDN_CMD_DIAL; - dev->mdm.dialing[info->line] = 1; - strcpy(dev->num[i], n); - isdn_info_update(); - dev->drv[info->isdn_driver]->interface->command(&cmd); - } else - restore_flags(flags); + info->isdn_driver = dev->drvmap[i]; + info->isdn_channel = dev->chanmap[i]; + info->drv_index = i; + dev->m_idx[i] = info->line; + dev->usage[i] |= ISDN_USAGE_OUTGOING; + isdn_info_update(); + restore_flags(flags); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_CLREAZ; + dev->drv[info->isdn_driver]->interface->command(&cmd); + strcpy(cmd.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETEAZ; + dev->drv[info->isdn_driver]->interface->command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL2; + cmd.arg = info->isdn_channel + (l2 << 8); + dev->drv[info->isdn_driver]->interface->command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL3; + cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8); + dev->drv[info->isdn_driver]->interface->command(&cmd); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + sprintf(cmd.num, "%s,%s,%d,%d", n, isdn_map_eaz2msn(m->msn, info->isdn_driver), + si, m->mdmreg[19]); + cmd.command = ISDN_CMD_DIAL; + info->dialing = 1; + strcpy(dev->num[i], n); + isdn_info_update(); + dev->drv[info->isdn_driver]->interface->command(&cmd); } } +/* isdn_tty_hangup() disassociates a tty from the real + * ISDN-line (hangup). The usage-status is cleared + * and some cleanup is done also. + */ void isdn_tty_modem_hup(modem_info * info) { isdn_ctrl cmd; + int usage; if (!info) return; - dev->mdm.rcvsched[info->line] = 0; - dev->mdm.online[info->line] = 0; + info->rcvsched = 0; + info->online = 0; + isdn_tty_cleanup_xmit(info); + switch (info->vonline) { + case 1: + /* voice-recording, add DLE-ETX */ + isdn_tty_at_cout("\020\003", info); + break; + case 2: + break; + } + info->vonline = 0; + if (info->adpcms) { + kfree(info->adpcms); + info->adpcms = NULL; + } + if (info->adpcmr) { + kfree(info->adpcmr); + info->adpcmr = NULL; + } + info->msr &= ~(UART_MSR_DCD | UART_MSR_RI); + info->lsr &= ~UART_LSR_TEMT; if (info->isdn_driver >= 0) { cmd.driver = info->isdn_driver; cmd.command = ISDN_CMD_HANGUP; cmd.arg = info->isdn_channel; dev->drv[info->isdn_driver]->interface->command(&cmd); isdn_all_eaz(info->isdn_driver, info->isdn_channel); - isdn_free_channel(info->isdn_driver, info->isdn_channel, ISDN_USAGE_MODEM); + usage = (info->emu.mdmreg[20] == 1)? + ISDN_USAGE_VOICE:ISDN_USAGE_MODEM; + isdn_free_channel(info->isdn_driver, info->isdn_channel, + usage); } info->isdn_driver = -1; info->isdn_channel = -1; if (info->drv_index >= 0) { - info->drv_index = -1; dev->m_idx[info->drv_index] = -1; + info->drv_index = -1; } } @@ -258,17 +489,20 @@ static void isdn_tty_change_speed(modem_info * info) i += 15; } if (quot) { - info->MCR |= UART_MCR_DTR; + info->mcr |= UART_MCR_DTR; + isdn_tty_modem_ncarrier(info); } else { - info->MCR &= ~UART_MCR_DTR; - isdn_tty_modem_reset_regs(&dev->mdm.atmodem[info->line], 0); + info->mcr &= ~UART_MCR_DTR; + if (info->emu.mdmreg[13] & 4) { #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in changespeed\n"); + printk(KERN_DEBUG "Mhup in changespeed\n"); #endif - isdn_tty_modem_hup(info); - if (dev->mdm.online[info->line]) - isdn_tty_modem_result(3, info); - return; + if (info->online) + info->ncarrier = 1; + isdn_tty_modem_reset_regs(&info->emu, 0); + isdn_tty_modem_hup(info); + } + return; } /* byte size and parity */ cval = cflag & (CSIZE | CSTOPB); @@ -297,11 +531,6 @@ static int isdn_tty_startup(modem_info * info) if (info->flags & ISDN_ASYNC_INITIALIZED) return 0; - if (!info->type) { - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - return 0; - } save_flags(flags); cli(); @@ -311,7 +540,7 @@ static int isdn_tty_startup(modem_info * info) /* * Now, initialize the UART */ - info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; + info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); /* @@ -320,10 +549,8 @@ static int isdn_tty_startup(modem_info * info) isdn_tty_change_speed(info); info->flags |= ISDN_ASYNC_INITIALIZED; - dev->mdm.msr[info->line] |= UART_MSR_DSR; -#if FUTURE + info->msr |= (UART_MSR_DSR | UART_MSR_CTS); info->send_outstanding = 0; -#endif restore_flags(flags); return 0; } @@ -344,12 +571,14 @@ static void isdn_tty_shutdown(modem_info * info) save_flags(flags); cli(); /* Disable interrupts */ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { - info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS); - isdn_tty_modem_reset_regs(&dev->mdm.atmodem[info->line], 0); + info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS); + if (info->emu.mdmreg[13] & 4) { + isdn_tty_modem_reset_regs(&info->emu, 0); #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n"); + printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n"); #endif - isdn_tty_modem_hup(info); + isdn_tty_modem_hup(info); + } } if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); @@ -358,12 +587,111 @@ static void isdn_tty_shutdown(modem_info * info) restore_flags(flags); } +#ifdef CONFIG_ISDN_AUDIO + + +int isdn_tty_countDLE(unsigned char *buf, int len) +{ + int count = 0; + + while (len--) + if (*buf++ == DLE) + count++; + return count; +} + +/* This routine is called wrom within isdn_tty_write() to perform + * DLE-decoding when sending audio-data. + */ +static int isdn_tty_handleDLEdown(modem_info *info, atemu *m, struct sk_buff *skb) +{ + unsigned char *p = skb->data; + int len = skb->len; + int count = 0; + + while (len>0) { + if (m->lastDLE) { + m->lastDLE = 0; + switch (*p) { + case DLE: + /* Escape code */ + if (len>1) + memmove(p,p+1,len-1); + p--; + count++; + break; + case ETX: + /* End of data */ + info->vonline = 0; + isdn_tty_at_cout("\r\nVCON\r\n",info); + return count; + case 'q': + case 's': + /* Silence */ + if (len>1) + memmove(p,p+1,len-1); + p--; + break; + } + } else { + if (*p == DLE) + m->lastDLE = 1; + else + count++; + } + p++; + len--; + } + if (len<0) { + printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n"); + return 0; + } + skb_trim(skb,count); + return count; +} + +/* This routine is called from within isdn_tty_write() when receiving + * audio-data. It interrupts receiving, if an character other than + * ^S or ^Q is sent. + */ +static int isdn_tty_end_vrx(const char *buf, int c, int from_user) +{ + char tmpbuf[VBUF]; + char *p; + + if (c > VBUF) { + printk(KERN_ERR "isdn_tty: (end_vrx) BUFFER OVERFLOW!!!\n"); + return 1; + } + if (from_user) { + memcpy_fromfs(tmpbuf, buf, c); + p = tmpbuf; + } else + p = (char *)buf; + while (c--) { + if ((*p != 0x11) && (*p != 0x13)) + return 1; + p++; + } + return 0; +} +#endif /* CONFIG_ISDN_AUDIO */ + +/* isdn_tty_write() is the main send-routine. It is called from the upper + * levels within the kernel to perform sending data. Depending on the + * online-flag it either directs output to the at-command-interpreter or + * to the lower level. Additional tasks done here: + * - If online, check for escape-sequence (+++) + * - If sending audio-data, call isdn_tty_DLEdown() to parse DLE-codes. + * - If receiving audio-data, call isdn_tty_end_vrx() to abor if needed. + * - If dialing, abort dial. + */ static int isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count) { int c, total = 0; - modem_info *info = (modem_info *) tty->driver_data; ulong flags; - int i; + modem_info *info = (modem_info *) tty->driver_data; + struct sk_buff *skb; if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write")) return 0; @@ -372,84 +700,79 @@ static int isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * save_flags(flags); cli(); while (1) { - c = MIN(count, info->xmit_size - info->xmit_count - 1); - if (info->isdn_driver >= 0) { -#if 0 - if (info->isdn_driver != 0) { - printk(KERN_DEBUG "FIDO: Zwei HW-Treiber geladen? Ansonsten ist was faul.\n"); - break; - } - int drvidx = info->isdn_driver; - driver *driv = dev->drv[drvidx]; - i = driv->maxbufsize; -#else - i = dev->drv[info->isdn_driver]->maxbufsize; -#endif - c = MIN(c, i); - } + c = MIN(count, info->xmit_size - info->xmit_count); + if (info->isdn_driver >= 0) + c = MIN(c, dev->drv[info->isdn_driver]->maxbufsize); if (c <= 0) break; - i = info->line; - if (dev->mdm.online[i]) { - isdn_tty_check_esc(buf, dev->mdm.atmodem[i].mdmreg[2], c, - &(dev->mdm.atmodem[i].pluscount), - &(dev->mdm.atmodem[i].lastplus), from_user); - if (from_user) - memcpy_fromfs(&(info->xmit_buf[info->xmit_count]), buf, c); - else - memcpy(&(info->xmit_buf[info->xmit_count]), buf, c); - info->xmit_count += c; - if (dev->mdm.atmodem[i].mdmreg[13] & 1) { - char *bufptr; - int buflen; -#if 0 - printk(KERN_DEBUG "WB1: %d\n", info->xmit_count); -#endif - bufptr = info->xmit_buf; - buflen = info->xmit_count; - if (dev->mdm.atmodem[i].mdmreg[13] & 2) { - /* Add T.70 simplified header */ - -#ifdef ISDN_DEBUG_MODEM_DUMP - isdn_dumppkt("T70pack1:", bufptr, buflen, 40); -#endif - bufptr -= 4; - buflen += 4; - memcpy(bufptr, "\1\0\1\0", 4); -#ifdef ISDN_DEBUG_MODEM_DUMP - isdn_dumppkt("T70pack2:", bufptr, buflen, 40); + if ((info->online > 1) || + (info->vonline == 2)) { + atemu *m = &info->emu; + + if (info->vonline != 2) + isdn_tty_check_esc(buf, m->mdmreg[2], c, + &(m->pluscount), + &(m->lastplus), + from_user); + if ((skb = alloc_skb(((info->vonline == 2)? + (c+(c<<2)):c)+16,GFP_ATOMIC))==NULL) { + printk(KERN_WARNING "isdn_tty: Cannot alloc skb in tty_write\n"); + restore_flags(flags); + return total; + } + skb_reserve(skb, 4); /* For T.70 header */ + if (from_user) + memcpy_fromfs(skb_put(skb, c), buf, c); + else + memcpy(skb_put(skb, c), buf, c); +#ifdef CONFIG_ISDN_AUDIO + if (info->vonline == 2) { + int cc = isdn_tty_handleDLEdown(info,m,skb); + info->xmit_count += cc; + if ((cc==0) && (c > 0)) { + /* If DLE decoding results in zero-transmit, but + * c originally was non-zero, do a wakeup. + */ + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); + wake_up_interruptible(&tty->write_wait); + } + } else #endif - } - if (isdn_writebuf_stub(info->isdn_driver, info->isdn_channel, bufptr, - buflen, 0) > 0) { - info->xmit_count = 0; - info->xmit_size = dev->mdm.atmodem[i].mdmreg[16] * 16; -#if FUTURE - info->send_outstanding++; - dev->mdm.msr[i] &= ~UART_MSR_CTS; -#endif - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); - wake_up_interruptible(&tty->write_wait); - } - } + info->xmit_count += c; + skb->users = c; + skb_queue_tail(info->xmit_buf,skb); + if (m->mdmreg[13] & 1) { + sti(); + isdn_tty_senddown(info); + } } else { - if (dev->mdm.dialing[i]) { - dev->mdm.dialing[i] = 0; + info->msr |= UART_MSR_CTS; + info->lsr |= UART_LSR_TEMT; +#ifdef CONFIG_ISDN_AUDIO + if (info->vonline == 1) { + if (isdn_tty_end_vrx(buf, c, from_user)) { + info->vonline = 0; + isdn_tty_at_cout("\020\003\r\nVCON\r\n", info); + } + } else +#endif + if (info->dialing) { + info->dialing = 0; #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in isdn_tty_write\n"); + printk(KERN_DEBUG "Mhup in isdn_tty_write\n"); #endif - isdn_tty_modem_hup(info); - isdn_tty_modem_result(3, info); - } else - c = isdn_tty_edit_at(buf, c, info, from_user); + isdn_tty_modem_result(3, info); + isdn_tty_modem_hup(info); + } else + c = isdn_tty_edit_at(buf, c, info, from_user); } buf += c; count -= c; total += c; } - if (info->xmit_count) + if (total) isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); restore_flags(flags); return total; @@ -462,9 +785,9 @@ static int isdn_tty_write_room(struct tty_struct *tty) if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write_room")) return 0; - if (!dev->mdm.online[info->line]) - return info->xmit_size - 1; - ret = info->xmit_size - info->xmit_count - 1; + if (!info->online) + return info->xmit_size; + ret = info->xmit_size - info->xmit_count; return (ret < 0) ? 0 : ret; } @@ -474,7 +797,7 @@ static int isdn_tty_chars_in_buffer(struct tty_struct *tty) if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_chars_in_buffer")) return 0; - if (!dev->mdm.online[info->line]) + if (!info->online) return 0; return (info->xmit_count); } @@ -482,14 +805,11 @@ static int isdn_tty_chars_in_buffer(struct tty_struct *tty) static void isdn_tty_flush_buffer(struct tty_struct *tty) { modem_info *info = (modem_info *) tty->driver_data; - uint flags; if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_buffer")) return; - save_flags(flags); - cli(); - info->xmit_count = 0; - restore_flags(flags); + isdn_tty_cleanup_xmit(info); + info->xmit_count = 0; wake_up_interruptible(&tty->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) @@ -502,7 +822,7 @@ static void isdn_tty_flush_chars(struct tty_struct *tty) if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_chars")) return; - if (info->xmit_count > 0) + if (skb_queue_len(info->xmit_buf)) isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); } @@ -522,7 +842,7 @@ static void isdn_tty_throttle(struct tty_struct *tty) return; if (I_IXOFF(tty)) info->x_char = STOP_CHAR(tty); - info->MCR &= ~UART_MCR_RTS; + info->mcr &= ~UART_MCR_RTS; } static void isdn_tty_unthrottle(struct tty_struct *tty) @@ -537,7 +857,7 @@ static void isdn_tty_unthrottle(struct tty_struct *tty) else info->x_char = START_CHAR(tty); } - info->MCR |= UART_MCR_RTS; + info->mcr |= UART_MCR_RTS; } /* @@ -564,7 +884,7 @@ static int isdn_tty_get_lsr_info(modem_info * info, uint * value) save_flags(flags); cli(); - status = dev->mdm.msr[info->line]; + status = info->lsr; restore_flags(flags); result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); put_fs_long(result, (ulong *) value); @@ -578,10 +898,10 @@ static int isdn_tty_get_modem_info(modem_info * info, uint * value) uint result; ulong flags; - control = info->MCR; + control = info->mcr; save_flags(flags); cli(); - status = dev->mdm.msr[info->line]; + status = info->msr; restore_flags(flags); result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) @@ -596,47 +916,66 @@ static int isdn_tty_get_modem_info(modem_info * info, uint * value) static int isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value) { uint arg = get_fs_long((ulong *) value); + int pre_dtr; switch (cmd) { - case TIOCMBIS: - if (arg & TIOCM_RTS) { - info->MCR |= UART_MCR_RTS; - } - if (arg & TIOCM_DTR) { - info->MCR |= UART_MCR_DTR; - } - break; - case TIOCMBIC: - if (arg & TIOCM_RTS) { - info->MCR &= ~UART_MCR_RTS; - } - if (arg & TIOCM_DTR) { - info->MCR &= ~UART_MCR_DTR; - isdn_tty_modem_reset_regs(&dev->mdm.atmodem[info->line], 0); + case TIOCMBIS: +#ifdef ISDN_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIS\n", info->line); +#endif + if (arg & TIOCM_RTS) { + info->mcr |= UART_MCR_RTS; + } + if (arg & TIOCM_DTR) { + info->mcr |= UART_MCR_DTR; + isdn_tty_modem_ncarrier(info); + } + break; + case TIOCMBIC: +#ifdef ISDN_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIC\n", info->line); +#endif + if (arg & TIOCM_RTS) { + info->mcr &= ~UART_MCR_RTS; + } + if (arg & TIOCM_DTR) { + info->mcr &= ~UART_MCR_DTR; + if (info->emu.mdmreg[13] & 4) { + isdn_tty_modem_reset_regs(&info->emu, 0); #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in TIOCMBIC\n"); + printk(KERN_DEBUG "Mhup in TIOCMBIC\n"); #endif - isdn_tty_modem_hup(info); - if (dev->mdm.online[info->line]) - isdn_tty_modem_result(3, info); - } - break; - case TIOCMSET: - info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR)) - | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) - | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); - if (!(info->MCR & UART_MCR_DTR)) { - isdn_tty_modem_reset_regs(&dev->mdm.atmodem[info->line], 0); + if (info->online) + info->ncarrier = 1; + isdn_tty_modem_hup(info); + } + } + break; + case TIOCMSET: +#ifdef ISDN_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "ttyI%d ioctl TIOCMSET\n", info->line); +#endif + pre_dtr = (info->mcr & UART_MCR_DTR); + info->mcr = ((info->mcr & ~(UART_MCR_RTS | UART_MCR_DTR)) + | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) + | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); + if (pre_dtr |= (info->mcr & UART_MCR_DTR)) { + if (!(info->mcr & UART_MCR_DTR)) { + if (info->emu.mdmreg[13] & 4) { + isdn_tty_modem_reset_regs(&info->emu, 0); #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in TIOCMSET\n"); + printk(KERN_DEBUG "Mhup in TIOCMSET\n"); #endif - isdn_tty_modem_hup(info); - if (dev->mdm.online[info->line]) - isdn_tty_modem_result(3, info); - } - break; - default: - return -EINVAL; + if (info->online) + info->ncarrier = 1; + isdn_tty_modem_hup(info); + } + } else + isdn_tty_modem_ncarrier(info); + } + break; + default: + return -EINVAL; } return 0; } @@ -651,104 +990,72 @@ static int isdn_tty_ioctl(struct tty_struct *tty, struct file *file, if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_ioctl")) return -ENODEV; switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - return 0; - case TIOCGSOFTCAR: - error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long)); - if (error) - return error; - put_fs_long(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg); - return 0; - case TIOCSSOFTCAR: - arg = get_fs_long((ulong *) arg); - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - return 0; - case TIOCMGET: - error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint)); - if (error) - return error; - return isdn_tty_get_modem_info(info, (uint *) arg); - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - return isdn_tty_set_modem_info(info, cmd, (uint *) arg); - case TIOCSERGETLSR: /* Get line status register */ - error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint)); - if (error) - return error; - else - return isdn_tty_get_lsr_info(info, (uint *) arg); - - case TIOCGSERIAL: - return -ENOIOCTLCMD; -#if 0 - error = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct serial_struct)); - if (error) - return error; - return get_serial_info(info, - (struct serial_struct *) arg); + case TCSBRK: /* SVID version: non-zero arg --> no break */ +#ifdef ISDN_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "ttyI%d ioctl TCSBRK\n", info->line); #endif - case TIOCSSERIAL: - return -ENOIOCTLCMD; -#if 0 - return set_serial_info(info, - (struct serial_struct *) arg); + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ +#ifdef ISDN_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "ttyI%d ioctl TCSBRKP\n", info->line); #endif - case TIOCSERCONFIG: - return -ENOIOCTLCMD; -#if 0 - return do_autoconfig(info); + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + return 0; + case TIOCGSOFTCAR: +#ifdef ISDN_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line); #endif - - case TIOCSERGWILD: - return -ENOIOCTLCMD; -#if 0 - error = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(int)); - if (error) - return error; - put_fs_long(modem_wild_int_mask, (ulong *) arg); - return 0; + error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long)); + if (error) + return error; + put_fs_long(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg); + return 0; + case TIOCSSOFTCAR: +#ifdef ISDN_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line); #endif - case TIOCSERSWILD: - return -ENOIOCTLCMD; -#if 0 - if (!suser()) - return -EPERM; - modem_wild_int_mask = get_fs_long((ulong *) arg); - if (modem_wild_int_mask < 0) - modem_wild_int_mask = check_wild_interrupts(0); - return 0; + arg = get_fs_long((ulong *) arg); + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + return 0; + case TIOCMGET: +#ifdef ISDN_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line); #endif - case TIOCSERGSTRUCT: - return -ENOIOCTLCMD; -#if 0 - error = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(modem_info)); - if (error) - return error; - memcpy_tofs((modem_info *) arg, - info, sizeof(modem_info)); - return 0; + error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint)); + if (error) + return error; + return isdn_tty_get_modem_info(info, (uint *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint)); + if (error) + return error; + return isdn_tty_set_modem_info(info, cmd, (uint *) arg); + case TIOCSERGETLSR: /* Get line status register */ +#ifdef ISDN_DEBUG_MODEM_IOCTL + printk(KERN_DEBUG "ttyI%d ioctl TIOSERGETLSR\n", info->line); #endif - default: + error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint)); + if (error) + return error; + else + return isdn_tty_get_lsr_info(info, (uint *) arg); + + default: #ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "unsupp. ioctl 0x%08x on ttyi%d\n", cmd, info->line); + printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line); #endif - return -ENOIOCTLCMD; + return -ENOIOCTLCMD; } return 0; } @@ -757,13 +1064,17 @@ static void isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_ter { modem_info *info = (modem_info *) tty->driver_data; - if (tty->termios->c_cflag == old_termios->c_cflag) - return; - isdn_tty_change_speed(info); - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - } + if (!old_termios) + isdn_tty_change_speed(info); + else { + if (tty->termios->c_cflag == old_termios->c_cflag) + return; + isdn_tty_change_speed(info); + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + } + } } /* @@ -817,7 +1128,8 @@ static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, m * If non-blocking mode is set, then make the check up front * and then exit. */ - if (filp->f_flags & O_NONBLOCK) { + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) return -EBUSY; info->flags |= ISDN_ASYNC_NORMAL_ACTIVE; @@ -865,9 +1177,7 @@ static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, m } if (!(info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) && !(info->flags & ISDN_ASYNC_CLOSING) && - (do_clocal || ( - dev->mdm.msr[info->line] & - UART_MSR_DCD))) { + (do_clocal || (info->msr & UART_MSR_DCD))) { break; } if (current->signal & ~current->blocked) { @@ -972,7 +1282,6 @@ static void isdn_tty_close(struct tty_struct *tty, struct file *filp) #endif return; } - dev->modempoll--; if ((tty->count == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty @@ -1007,8 +1316,7 @@ static void isdn_tty_close(struct tty_struct *tty, struct file *filp) if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) info->callout_termios = *tty->termios; - tty->closing = 1; - + tty->closing = 1; /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the @@ -1023,8 +1331,7 @@ static void isdn_tty_close(struct tty_struct *tty, struct file *filp) * important if there is a transmit FIFO! */ timeout = jiffies + HZ; - while (!(dev->mdm.mlr[info->line] - & UART_LSR_TEMT)) { + while (!(info->lsr & UART_LSR_TEMT)) { current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + 20; schedule(); @@ -1032,6 +1339,7 @@ static void isdn_tty_close(struct tty_struct *tty, struct file *filp) break; } } + dev->modempoll--; isdn_tty_shutdown(info); if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); @@ -1039,22 +1347,10 @@ static void isdn_tty_close(struct tty_struct *tty, struct file *filp) tty->ldisc.flush_buffer(tty); info->tty = 0; tty->closing = 0; -#if 00 - if (tty->ldisc.num != ldiscs[N_TTY].num) { - if (tty->ldisc.close) - (tty->ldisc.close) (tty); - tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; - if (tty->ldisc.open) - (tty->ldisc.open) (tty); - } -#endif if (info->blocked_open) { - if (info->close_delay) { - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->close_delay; - schedule(); - } + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 50; + schedule(); wake_up_interruptible(&info->open_wait); } info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE | @@ -1082,6 +1378,8 @@ static void isdn_tty_hangup(struct tty_struct *tty) wake_up_interruptible(&info->open_wait); } +/* This routine initializes all emulator-data. + */ static void isdn_tty_reset_profile(atemu * m) { m->profile[0] = 0; @@ -1097,22 +1395,32 @@ static void isdn_tty_reset_profile(atemu * m) m->profile[10] = 7; m->profile[11] = 70; m->profile[12] = 0x45; - m->profile[13] = 0; + m->profile[13] = 4; m->profile[14] = ISDN_PROTO_L2_X75I; m->profile[15] = ISDN_PROTO_L3_TRANS; m->profile[16] = ISDN_SERIAL_XMIT_SIZE / 16; m->profile[17] = ISDN_MODEM_WINSIZE; - m->profile[18] = 7; + m->profile[18] = 4; m->profile[19] = 0; + m->profile[20] = 0; m->pmsn[0] = '\0'; } +static void isdn_tty_modem_reset_vpar(atemu *m) +{ + m->vpar[0] = 2; /* Voice-device (2 = phone line) */ + m->vpar[1] = 0; /* Silence detection level (0 = none ) */ + m->vpar[2] = 70; /* Silence interval (7 sec. ) */ + m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */ +} + static void isdn_tty_modem_reset_regs(atemu * m, int force) { if ((m->mdmreg[12] & 32) || force) { memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG); memcpy(m->msn, m->pmsn, ISDN_MSNLEN); } + isdn_tty_modem_reset_vpar(m); m->mdmcmdl = 0; } @@ -1131,10 +1439,6 @@ int isdn_tty_modem_init(void) modem_info *info; m = &dev->mdm; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - isdn_tty_reset_profile(&(m->atmodem[i])); - isdn_tty_modem_reset_regs(&(m->atmodem[i]), 1); - } memset(&m->tty_modem, 0, sizeof(struct tty_driver)); m->tty_modem.magic = TTY_DRIVER_MAGIC; m->tty_modem.name = isdn_ttyname_ttyI; @@ -1148,8 +1452,8 @@ int isdn_tty_modem_init(void) m->tty_modem.flags = TTY_DRIVER_REAL_RAW; m->tty_modem.refcount = &m->refcount; m->tty_modem.table = m->modem_table; - m->tty_modem.termios = m->modem_termios; - m->tty_modem.termios_locked = m->modem_termios_locked; + m->tty_modem.termios = (struct termios **)m->modem_termios; + m->tty_modem.termios_locked = (struct termios **)m->modem_termios_locked; m->tty_modem.open = isdn_tty_open; m->tty_modem.close = isdn_tty_close; m->tty_modem.write = isdn_tty_write; @@ -1184,11 +1488,12 @@ int isdn_tty_modem_init(void) return -2; } for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - info = &(m->info[i]); + info = &m->info[i]; + isdn_tty_reset_profile(&info->emu); + isdn_tty_modem_reset_regs(&info->emu, 1); info->magic = ISDN_ASYNC_MAGIC; info->line = i; info->tty = 0; - info->close_delay = 50; info->x_char = 0; info->count = 0; info->blocked_open = 0; @@ -1196,16 +1501,15 @@ int isdn_tty_modem_init(void) info->normal_termios = m->tty_modem.init_termios; info->open_wait = 0; info->close_wait = 0; - info->type = ISDN_PORT_16550A; info->isdn_driver = -1; info->isdn_channel = -1; info->drv_index = -1; info->xmit_size = ISDN_SERIAL_XMIT_SIZE; - if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_SIZE + 5, GFP_KERNEL))) { + if (!(info->xmit_buf = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL))) { printk(KERN_ERR "Could not allocate modem xmit-buffer\n"); return -3; } - info->xmit_buf += 4; /* Make room for T.70 header */ + skb_queue_head_init(info->xmit_buf); } return 0; } @@ -1261,16 +1565,16 @@ int isdn_tty_find_icall(int di, int ch, char *num) printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2); #endif for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + modem_info *info = &dev->mdm.info[i]; #ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: i=%d msn=%s mmsn=%s mreg18=%d mreg19=%d\n", i, - dev->mdm.atmodem[i].msn, isdn_map_eaz2msn(dev->mdm.atmodem[i].msn, di), - dev->mdm.atmodem[i].mdmreg[18], dev->mdm.atmodem[i].mdmreg[19]); + info->emu.msn, isdn_map_eaz2msn(info->emu.msn, di), + info->emu.mdmreg[18], info->emu.mdmreg[19]); #endif - if ((!strcmp(isdn_map_eaz2msn(dev->mdm.atmodem[i].msn, di) - ,eaz)) && /* EAZ is matching */ - (dev->mdm.atmodem[i].mdmreg[18] == si1) && /* SI1 is matching */ - (dev->mdm.atmodem[i].mdmreg[19] == si2)) { /* SI2 is matching */ - modem_info *info = &dev->mdm.info[i]; + if ((!strcmp(isdn_map_eaz2msn(info->emu.msn, di), + eaz)) && /* EAZ is matching */ + (info->emu.mdmreg[18] & si2bit[si1]) && /* SI1 is matching */ + ((info->emu.mdmreg[19] == si2) || !si2)) { /* SI2 is matching or 0 */ idx = isdn_dc2minor(di, ch); #ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: match1\n"); @@ -1287,8 +1591,9 @@ int isdn_tty_find_icall(int di, int ch, char *num) info->drv_index = idx; dev->m_idx[idx] = info->line; dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE; - dev->usage[idx] |= ISDN_USAGE_MODEM; + dev->usage[idx] |= (si1==1)?ISDN_USAGE_VOICE:ISDN_USAGE_MODEM; strcpy(dev->num[idx], nr); + info->emu.mdmreg[20] = si2bit[si1]; isdn_info_update(); restore_flags(flags); printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr, @@ -1316,7 +1621,7 @@ int isdn_tty_find_icall(int di, int ch, char *num) static void isdn_tty_at_cout(char *msg, modem_info * info) { struct tty_struct *tty; - atemu *m = &(dev->mdm.atmodem[info->line]); + atemu *m = &info->emu; char *p; char c; ulong flags; @@ -1330,17 +1635,17 @@ static void isdn_tty_at_cout(char *msg, modem_info * info) tty = info->tty; for (p = msg; *p; p++) { switch (*p) { - case '\r': - c = m->mdmreg[3]; - break; - case '\n': - c = m->mdmreg[4]; - break; - case '\b': - c = m->mdmreg[5]; - break; - default: - c = *p; + case '\r': + c = m->mdmreg[3]; + break; + case '\n': + c = m->mdmreg[4]; + break; + case '\b': + c = m->mdmreg[5]; + break; + default: + c = *p; } if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) { restore_flags(flags); @@ -1363,8 +1668,8 @@ static void isdn_tty_on_hook(modem_info * info) #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n"); #endif - isdn_tty_modem_hup(info); isdn_tty_modem_result(3, info); + isdn_tty_modem_hup(info); } } @@ -1433,43 +1738,45 @@ static void isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pl */ void isdn_tty_modem_result(int code, modem_info * info) { - atemu *m = &dev->mdm.atmodem[info->line]; + atemu *m = &info->emu; static char *msg[] = {"OK", "CONNECT", "RING", "NO CARRIER", "ERROR", "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER", - "RINGING", "NO MSN/EAZ"}; + "RINGING", "NO MSN/EAZ", "VCON"}; ulong flags; char s[4]; switch (code) { - case 2: - m->mdmreg[1]++; /* RING */ - if (m->mdmreg[1] == m->mdmreg[0]) { - /* Accept incoming call */ - isdn_ctrl cmd; - m->mdmreg[1] = 0; - dev->mdm.msr[info->line] &= ~UART_MSR_RI; - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_ACCEPTD; - dev->drv[info->isdn_driver]->interface->command(&cmd); - } - break; - case 3: - /* NO CARRIER */ - save_flags(flags); - cli(); - dev->mdm.msr[info->line] &= ~(UART_MSR_DCD | UART_MSR_RI); - if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) { - restore_flags(flags); - return; - } - restore_flags(flags); - break; - case 1: - case 5: - dev->mdm.online[info->line] = 1; - break; + case 2: + m->mdmreg[1]++; /* RING */ + if (m->mdmreg[1] == m->mdmreg[0]) + /* Automatically accept incoming call */ + isdn_tty_cmd_ATA(info); + break; + case 3: + /* NO CARRIER */ + save_flags(flags); + cli(); +#ifdef ISDN_DEBUG_MODEM_HUP + printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n", + (info->flags & ISDN_ASYNC_CLOSING), + (!info->tty)); +#endif + if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) { + restore_flags(flags); + return; + } + restore_flags(flags); + break; + case 1: + case 5: + if (!info->online) + info->online = 2; + break; + case 11: + if (!info->online) + info->online = 1; + break; } if (m->mdmreg[12] & 1) { /* Show results */ @@ -1503,8 +1810,9 @@ void isdn_tty_modem_result(int code, modem_info * info) } if ((info->flags & ISDN_ASYNC_CHECK_CD) && (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) && - (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) + (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) { tty_hangup(info->tty); + } restore_flags(flags); } } @@ -1516,7 +1824,7 @@ static void isdn_tty_show_profile(int ridx, modem_info * info) { char v[6]; - sprintf(v, "%d\r\n", dev->mdm.atmodem[info->line].mdmreg[ridx]); + sprintf(v, "\r\n%d", info->emu.mdmreg[ridx]); isdn_tty_at_cout(v, info); } @@ -1546,319 +1854,594 @@ static void isdn_tty_getdial(char *p, char *q) *q = 0; } +#define PARSE_ERROR { isdn_tty_modem_result(4, info); return; } +#define PARSE_ERROR1 { isdn_tty_modem_result(4, info); return 1; } + +/* + * Parse AT&.. commands. + */ +static int isdn_tty_cmd_ATand(char **p, modem_info * info) +{ + atemu *m = &info->emu; + int i; + char rb[100]; + + switch (*p[0]) { + case 'B': + /* &B - Set Buffersize */ + p[0]++; + i = isdn_getnum(p); + if ((i < 0) || (i > ISDN_SERIAL_XMIT_SIZE)) + PARSE_ERROR1; +#ifdef CONFIG_ISDN_AUDIO + if ((m->mdmreg[18] & 1) && (i > VBUF)) + PARSE_ERROR1; +#endif + m->mdmreg[16] = i / 16; + info->xmit_size = m->mdmreg[16] * 16; + break; + case 'D': + /* &D - Set DCD-Low-behavior */ + p[0]++; + switch (isdn_getnum(p)) { + case 0: + m->mdmreg[13] &= ~4; + break; + case 2: + m->mdmreg[13] |= 4; + m->mdmreg[12] &= ~32; + break; + case 3: + m->mdmreg[13] |= 4; + m->mdmreg[12] |= 32; + break; + default: + PARSE_ERROR1 + } + break; + case 'E': + /* &E -Set EAZ/MSN */ + p[0]++; + isdn_tty_get_msnstr(m->msn, p); + break; + case 'F': + /* &F -Set Factory-Defaults */ + p[0]++; + isdn_tty_reset_profile(m); + isdn_tty_modem_reset_regs(m, 1); + break; + case 'S': + /* &S - Set Windowsize */ + p[0]++; + i = isdn_getnum(p); + if ((i > 0) && (i < 9)) + m->mdmreg[17] = i; + else + PARSE_ERROR1; + break; + case 'V': + /* &V - Show registers */ + p[0]++; + for (i = 0; i < ISDN_MODEM_ANZREG; i++) { + sprintf(rb, "S%d=%d%s", i, + m->mdmreg[i], (i == 6) ? "\r\n" : " "); + isdn_tty_at_cout(rb, info); + } + sprintf(rb, "\r\nEAZ/MSN: %s\r\n", + strlen(m->msn) ? m->msn : "None"); + isdn_tty_at_cout(rb, info); + break; + case 'W': + /* &W - Write Profile */ + p[0]++; + switch (*p[0]) { + case '0': + p[0]++; + modem_write_profile(m); + break; + default: + PARSE_ERROR1; + } + break; + case 'X': + /* &X - Switch to BTX-Mode */ + p[0]++; + switch (isdn_getnum(p)) { + case 0: + m->mdmreg[13] &= ~2; + break; + case 1: + m->mdmreg[13] |= 2; + m->mdmreg[14] = 0; + m->mdmreg[16] = 7; + info->xmit_size = 112; + m->mdmreg[18] = 4; + m->mdmreg[19] = 0; + break; + default: + PARSE_ERROR1; + } + break; + default: + PARSE_ERROR1; + } + return 0; +} + +/* + * Perform ATS command + */ +static int isdn_tty_cmd_ATS(char **p, modem_info * info) +{ + atemu *m = &info->emu; + int mreg; + int mval; + + mreg = isdn_getnum(p); + if (mreg < 0 || mreg > ISDN_MODEM_ANZREG) + PARSE_ERROR1; + switch (*p[0]) { + case '=': + p[0]++; + mval = isdn_getnum(p); + if (mval < 0 || mval > 255) + PARSE_ERROR1; + switch (mreg) { + /* Some plausibility checks */ + case 14: + if (mval > ISDN_PROTO_L2_TRANS) + PARSE_ERROR1; + break; + case 16: + if ((mval * 16) > ISDN_SERIAL_XMIT_SIZE) + PARSE_ERROR1; +#ifdef CONFIG_ISDN_AUDIO + if ((m->mdmreg[18] & 1) && (mval > VBUFX)) + PARSE_ERROR1; +#endif + info->xmit_size = mval * 16; + break; + case 20: + PARSE_ERROR1; + } + m->mdmreg[mreg] = mval; + break; + case '?': + p[0]++; + isdn_tty_show_profile(mreg, info); + break; + default: + PARSE_ERROR1; + break; + } + return 0; +} + +/* + * Perform ATA command + */ +static void isdn_tty_cmd_ATA(modem_info * info) +{ + atemu *m = &info->emu; + isdn_ctrl cmd; + int l2; + + if (info->msr & UART_MSR_RI) { + /* Accept incoming call */ + m->mdmreg[1] = 0; + info->msr &= ~UART_MSR_RI; + l2 = m->mdmreg[14]; +#ifdef CONFIG_ISDN_AUDIO + /* If more than one bit set in reg18, autoselect Layer2 */ + if ((m->mdmreg[18] & m->mdmreg[20]) != m->mdmreg[18]) + if (m->mdmreg[20] == 1) l2 = 4; +#endif + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL2; + cmd.arg = info->isdn_channel + (l2 << 8); + dev->drv[info->isdn_driver]->interface->command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL3; + cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8); + dev->drv[info->isdn_driver]->interface->command(&cmd); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_ACCEPTD; + dev->drv[info->isdn_driver]->interface->command(&cmd); + } else + isdn_tty_modem_result(8, info); +} + +#ifdef CONFIG_ISDN_AUDIO +/* + * Parse AT+V.. commands + */ +static int isdn_tty_cmd_PLUSV(char **p, modem_info * info) +{ + atemu *m = &info->emu; + static char *vcmd[] = {"NH","IP","LS","RX","SD","SM","TX",NULL}; + int i; + int par1; + int par2; + char rs[20]; + + i = 0; + while (vcmd[i]) { + if (!strncmp(vcmd[i],p[0],2)) { + p[0] += 2; + break; + } + i++; + } + switch (i) { + case 0: + /* AT+VNH - Auto hangup feature */ + switch (*p[0]) { + case '?': + p[0]++; + isdn_tty_at_cout("\r\n1", info); + break; + case '=': + p[0]++; + switch (*p[0]) { + case '1': + p[0]++; + break; + case '?': + p[0]++; + isdn_tty_at_cout("\r\n1", info); + break; + default: + PARSE_ERROR1; + } + break; + default: + PARSE_ERROR1; + } + break; + case 1: + /* AT+VIP - Reset all voice parameters */ + isdn_tty_modem_reset_vpar(m); + break; + case 2: + /* AT+VLS - Select device, accept incoming call */ + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs,"\r\n%d",m->vpar[0]); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + switch (*p[0]) { + case '0': + p[0]++; + m->vpar[0] = 0; + break; + case '2': + p[0]++; + m->vpar[0] = 2; + break; + case '?': + p[0]++; + isdn_tty_at_cout("\r\n0,2", info); + break; + default: + PARSE_ERROR1; + } + break; + default: + PARSE_ERROR1; + } + break; + case 3: + /* AT+VRX - Start recording */ + if (!m->vpar[0]) + PARSE_ERROR1; + if (m->vpar[3] < 5) { + info->adpcmr = isdn_audio_adpcm_init(m->vpar[3]); + if (!info->adpcmr) { + printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n"); + PARSE_ERROR1; + } + } + info->vonline = 1; + isdn_tty_modem_result(1, info); + return 1; + break; + case 4: + /* AT+VSD - Silence detection */ + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs,"\r\n<%d>,<%d>", + m->vpar[1], + m->vpar[2]); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + switch (*p[0]) { + case '0': + case '1': + case '2': + case '3': + par1 = isdn_getnum(p); + if ((par1 < 0) || (par1 > 31)) + PARSE_ERROR1; + if (*p[0] != ',') + PARSE_ERROR1; + p[0]++; + par2 = isdn_getnum(p); + if ((par2 < 0) || (par2 > 255)) + PARSE_ERROR1; + m->vpar[1] = par1; + m->vpar[2] = par2; + break; + case '?': + p[0]++; + isdn_tty_at_cout("\r\n<0-31>,<0-255>", + info); + break; + default: + PARSE_ERROR1; + } + break; + default: + PARSE_ERROR1; + } + break; + case 5: + /* AT+VSM - Select compression */ + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs,"\r\n<%d>,<%d><8000>", + m->vpar[3], + m->vpar[1]); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + switch (*p[0]) { + case '2': + case '3': + case '4': + case '5': + case '6': + par1 = isdn_getnum(p); + if ((par1 < 2) || (par1 > 6)) + PARSE_ERROR1; + m->vpar[3] = par1; + break; + case '?': + p[0]++; + isdn_tty_at_cout("\r\n2;ADPCM;2;0;(8000)\r\n", + info); + isdn_tty_at_cout("3;ADPCM;3;0;(8000)\r\n", + info); + isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n", + info); + isdn_tty_at_cout("5;ALAW;8;0;(8000)", + info); + isdn_tty_at_cout("6;ULAW;8;0;(8000)", + info); + break; + default: + PARSE_ERROR1; + } + break; + default: + PARSE_ERROR1; + } + break; + case 6: + /* AT+VTX - Start sending */ + if (!m->vpar[0]) + PARSE_ERROR1; + if (m->vpar[3] < 5) { + info->adpcms = isdn_audio_adpcm_init(m->vpar[3]); + if (!info->adpcms) { + printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n"); + PARSE_ERROR1; + } + } + info->vonline = 2; + isdn_tty_modem_result(1, info); + return 1; + break; + default: + PARSE_ERROR1; + } + return 0; +} +#endif /* CONFIG_ISDN_AUDIO */ + /* * Parse and perform an AT-command-line. - * - * Parameter: - * channel index to line (minor-device) */ static void isdn_tty_parse_at(modem_info * info) { - atemu *m = &dev->mdm.atmodem[info->line]; - char *p; - int mreg; - int mval; - int i; - char rb[100]; - char ds[40]; - isdn_ctrl cmd; + atemu *m = &info->emu; + char *p; + char ds[40]; #ifdef ISDN_DEBUG_AT - printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd); -#endif - for (p = &m->mdmcmd[2]; *p;) { - switch (*p) { - case 'A': - /* A - Accept incoming call */ - p++; - if (dev->mdm.msr[info->line] & UART_MSR_RI) { -#define FIDOBUG -#ifdef FIDOBUG -/* Variables fido... defined temporarily for finding a strange bug */ - driver *fido_drv; - isdn_if *fido_if; - int fido_isdn_driver; - modem_info *fido_modem_info; - int (*fido_command) (isdn_ctrl *); -#endif - /* Accept incoming call */ - m->mdmreg[1] = 0; - dev->mdm.msr[info->line] &= ~UART_MSR_RI; - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL2; - cmd.arg = info->isdn_channel + (m->mdmreg[14] << 8); - dev->drv[info->isdn_driver]->interface->command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8); - dev->drv[info->isdn_driver]->interface->command(&cmd); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_ACCEPTD; -#ifdef FIDOBUG - fido_modem_info = info; - fido_isdn_driver = fido_modem_info->isdn_driver; - fido_drv = dev->drv[fido_isdn_driver]; - fido_if = fido_drv->interface; - fido_command = fido_if->command; - fido_command(&cmd); -#else - dev->drv[info->isdn_driver]->interface->command(&cmd); + printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd); #endif - } else { - isdn_tty_modem_result(8, info); - return; - } - break; - case 'D': - /* D - Dial */ - isdn_tty_getdial(++p, ds); - p += strlen(p); - if (!strlen(m->msn)) - isdn_tty_modem_result(10, info); - else if (strlen(ds)) - isdn_tty_dial(ds, info, m); - else - isdn_tty_modem_result(4, info); - return; - case 'E': - /* E - Turn Echo on/off */ - p++; - switch (*p) { - case '0': - p++; - m->mdmreg[12] &= ~4; - break; - case '1': - p++; - m->mdmreg[12] |= 4; - break; - default: - isdn_tty_modem_result(4, info); - return; - } - break; - case 'H': - /* H - On/Off-hook */ - p++; - switch (*p) { - case '0': - p++; - isdn_tty_on_hook(info); - break; - case '1': - p++; - isdn_tty_off_hook(); - break; - default: - isdn_tty_on_hook(info); - break; - } - break; - case 'I': - /* I - Information */ - p++; - isdn_tty_at_cout("ISDN for Linux (c) by Fritz Elfert\r\n", info); - switch (*p) { - case '0': - case '1': - p++; - break; - default: - } - break; - case 'O': - /* O - Go online */ - p++; - if (dev->mdm.msr[info->line] & UART_MSR_DCD) /* if B-Channel is up */ - isdn_tty_modem_result(5, info); - else - isdn_tty_modem_result(3, info); - return; - case 'Q': - /* Q - Turn Emulator messages on/off */ - p++; - switch (*p) { - case '0': - p++; - m->mdmreg[12] |= 1; - break; - case '1': - p++; - m->mdmreg[12] &= ~1; - break; - default: - isdn_tty_modem_result(4, info); - return; - } - break; - case 'S': - /* S - Set/Get Register */ - p++; - mreg = isdn_getnum(&p); - if (mreg < 0 || mreg > ISDN_MODEM_ANZREG) { - isdn_tty_modem_result(4, info); - return; - } - switch (*p) { - case '=': - p++; - mval = isdn_getnum(&p); - if (mval >= 0 && mval <= 255) { - if ((mreg == 16) && ((mval * 16) > ISDN_SERIAL_XMIT_SIZE)) { - isdn_tty_modem_result(4, info); - return; - } - m->mdmreg[mreg] = mval; - } else { - isdn_tty_modem_result(4, info); - return; - } - break; - case '?': - p++; - isdn_tty_show_profile(mreg, info); - return; - break; - default: - isdn_tty_modem_result(4, info); - return; - } - break; - case 'V': - /* V - Numeric or ASCII Emulator-messages */ - p++; - switch (*p) { - case '0': - p++; - m->mdmreg[12] |= 2; - break; - case '1': - p++; - m->mdmreg[12] &= ~2; - break; - default: - isdn_tty_modem_result(4, info); - return; - } - break; - case 'Z': - /* Z - Load Registers from Profile */ - p++; - isdn_tty_modem_reset_regs(m, 1); - break; - case '+': - p++; - switch (*p) { - case 'F': - break; - } - break; - case '&': - p++; - switch (*p) { - case 'B': - /* &B - Set Buffersize */ - p++; - i = isdn_getnum(&p); - if ((i < 0) || (i > ISDN_SERIAL_XMIT_SIZE)) { - isdn_tty_modem_result(4, info); - return; - } - m->mdmreg[16] = i / 16; - break; - case 'D': - /* &D - Set DCD-Low-behavior */ - p++; - switch (isdn_getnum(&p)) { - case 2: - m->mdmreg[12] &= ~32; - break; - case 3: - m->mdmreg[12] |= 32; - break; - default: - isdn_tty_modem_result(4, info); - return; - } - break; - case 'E': - /* &E -Set EAZ/MSN */ - p++; - isdn_tty_get_msnstr(m->msn, &p); - break; - case 'F': - /* &F -Set Factory-Defaults */ - p++; - isdn_tty_reset_profile(m); - isdn_tty_modem_reset_regs(m, 1); - break; - case 'S': - /* &S - Set Windowsize */ - p++; - i = isdn_getnum(&p); - if ((i > 0) && (i < 9)) - m->mdmreg[17] = i; - else { - isdn_tty_modem_result(4, info); - return; - } - break; - case 'V': - /* &V - Show registers */ - p++; - for (i = 0; i < ISDN_MODEM_ANZREG; i++) { - sprintf(rb, "S%d=%d%s", i, m->mdmreg[i], (i == 6) ? "\r\n" : " "); - isdn_tty_at_cout(rb, info); - } - sprintf(rb, "\r\nEAZ/MSN: %s\r\n", strlen(m->msn) ? m->msn : "None"); - isdn_tty_at_cout(rb, info); - break; - case 'W': - /* &W - Write Profile */ - p++; - switch (*p) { - case '0': - p++; - modem_write_profile(m); - break; - default: - isdn_tty_modem_result(4, info); - return; - } - break; - case 'X': - /* &X - Switch to BTX-Mode */ - p++; - switch (*p) { - case '0': - p++; - m->mdmreg[13] &= ~2; - break; - case '1': - p++; - m->mdmreg[13] |= 2; - m->mdmreg[14] = 0; - m->mdmreg[16] = 7; - m->mdmreg[18] = 7; - m->mdmreg[19] = 0; - break; - default: - isdn_tty_modem_result(4, info); - return; - } - break; - default: - isdn_tty_modem_result(4, info); - return; - } - break; - default: - isdn_tty_modem_result(4, info); - return; - } - } - isdn_tty_modem_result(0, info); + for (p = &m->mdmcmd[2]; *p;) { + switch (*p) { + case 'A': + /* A - Accept incoming call */ + p++; + isdn_tty_cmd_ATA(info); + return; + break; + case 'D': + /* D - Dial */ + isdn_tty_getdial(++p, ds); + p += strlen(p); + if (!strlen(m->msn)) + isdn_tty_modem_result(10, info); + else if (strlen(ds)) + isdn_tty_dial(ds, info, m); + else + isdn_tty_modem_result(4, info); + return; + case 'E': + /* E - Turn Echo on/off */ + p++; + switch (isdn_getnum(&p)) { + case 0: + m->mdmreg[12] &= ~4; + break; + case 1: + m->mdmreg[12] |= 4; + break; + default: + PARSE_ERROR; + } + break; + case 'H': + /* H - On/Off-hook */ + p++; + switch (*p) { + case '0': + p++; + isdn_tty_on_hook(info); + break; + case '1': + p++; + isdn_tty_off_hook(); + break; + default: + isdn_tty_on_hook(info); + break; + } + break; + case 'I': + /* I - Information */ + p++; + isdn_tty_at_cout("\r\nLinux ISDN", info); + switch (*p) { + case '0': + case '1': + p++; + break; + default: + } + break; + case 'O': + /* O - Go online */ + p++; + if (info->msr & UART_MSR_DCD) + /* if B-Channel is up */ + isdn_tty_modem_result(5, info); + else + isdn_tty_modem_result(3, info); + return; + case 'Q': + /* Q - Turn Emulator messages on/off */ + p++; + switch (isdn_getnum(&p)) { + case 0: + m->mdmreg[12] |= 1; + break; + case 1: + m->mdmreg[12] &= ~1; + break; + default: + PARSE_ERROR; + } + break; + case 'S': + /* S - Set/Get Register */ + p++; + if (isdn_tty_cmd_ATS(&p, info)) + return; + break; + case 'V': + /* V - Numeric or ASCII Emulator-messages */ + p++; + switch (isdn_getnum(&p)) { + case 0: + m->mdmreg[12] |= 2; + break; + case 1: + m->mdmreg[12] &= ~2; + break; + default: + PARSE_ERROR; + } + break; + case 'Z': + /* Z - Load Registers from Profile */ + p++; + isdn_tty_modem_reset_regs(m, 1); + break; +#ifdef CONFIG_ISDN_AUDIO + case '+': + p++; + switch (*p) { + case 'F': + if (strncmp(p,"FCLASS",6)) + PARSE_ERROR; + p += 6; + switch (*p) { + case '?': + p++; + sprintf(ds,"\r\n%d", + (m->mdmreg[18]&1)?8:0); + isdn_tty_at_cout(ds, info); + break; + case '=': + p++; + switch (*p) { + case '0': + p++; + m->mdmreg[18] = 4; + break; + case '8': + p++; + m->mdmreg[18] = 5; + m->mdmreg[16] = VBUFX; + info->xmit_size = VBUF; + break; + case '?': + p++; + isdn_tty_at_cout("\r\n0,8", + info); + break; + default: + PARSE_ERROR; + } + break; + default: + PARSE_ERROR; + + } + break; + case 'V': + if (!(m->mdmreg[18] & 1)) + PARSE_ERROR; + p++; + if (isdn_tty_cmd_PLUSV(&p, info)) + return; + break; + } + break; +#endif /* CONFIG_ISDN_AUDIO */ + case '&': + p++; + if (isdn_tty_cmd_ATand(&p, info)) + return; + break; + default: + isdn_tty_modem_result(4, info); + return; + } + } + isdn_tty_modem_result(0, info); } /* Need own toupper() because standard-toupper is not available @@ -1877,7 +2460,7 @@ static void isdn_tty_parse_at(modem_info * info) */ static int isdn_tty_edit_at(const char *p, int count, modem_info * info, int user) { - atemu *m = &dev->mdm.atmodem[info->line]; + atemu *m = &info->emu; int total = 0; u_char c; char eb[2]; @@ -1921,16 +2504,16 @@ static int isdn_tty_edit_at(const char *p, int count, modem_info * info, int use if (m->mdmcmdl < 255) { c = my_toupper(c); switch (m->mdmcmdl) { - case 0: - if (c == 'A') - m->mdmcmd[m->mdmcmdl++] = c; - break; - case 1: - if (c == 'T') - m->mdmcmd[m->mdmcmdl++] = c; - break; - default: - m->mdmcmd[m->mdmcmdl++] = c; + case 0: + if (c == 'A') + m->mdmcmd[m->mdmcmdl++] = c; + break; + case 1: + if (c == 'T') + m->mdmcmd[m->mdmcmdl++] = c; + break; + default: + m->mdmcmd[m->mdmcmdl++] = c; } } } @@ -1952,16 +2535,18 @@ void isdn_tty_modem_escape(void) for (i = 0; i < ISDN_MAX_CHANNELS; i++) if (USG_MODEM(dev->usage[i])) - if ((midx = dev->m_idx[i]) >= 0) - if (dev->mdm.online[midx]) { + if ((midx = dev->m_idx[i]) >= 0) { + modem_info *info = &dev->mdm.info[midx]; + if (info->online) { ton = 1; - if ((dev->mdm.atmodem[midx].pluscount == 3) && - ((jiffies - dev->mdm.atmodem[midx].lastplus) > PLUSWAIT2)) { - dev->mdm.atmodem[midx].pluscount = 0; - dev->mdm.online[midx] = 0; - isdn_tty_modem_result(0, &dev->mdm.info[midx]); + if ((info->emu.pluscount == 3) && + ((jiffies - info->emu.lastplus) > PLUSWAIT2)) { + info->emu.pluscount = 0; + info->online = 0; + isdn_tty_modem_result(0, info); } } + } isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton); } @@ -1977,76 +2562,46 @@ void isdn_tty_modem_ring(void) int midx; for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (USG_MODEM(dev->usage[i])) - if ((midx = dev->m_idx[i]) >= 0) - if (dev->mdm.msr[midx] & UART_MSR_RI) { + if (USG_MODEMORVOICE(dev->usage[i])) + if ((midx = dev->m_idx[i]) >= 0) { + modem_info *info = &dev->mdm.info[midx]; + if (info->msr & UART_MSR_RI) { ton = 1; - isdn_tty_modem_result(2, &dev->mdm.info[midx]); + isdn_tty_modem_result(2, info); } + } isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton); } +/* + * For all online tty's, try sending data to + * the lower levels. + */ void isdn_tty_modem_xmit(void) { int ton = 0; int i; int midx; - char *bufptr; - int buflen; for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (USG_MODEM(dev->usage[i])) - if ((midx = dev->m_idx[i]) >= 0) - if (dev->mdm.online[midx]) { - modem_info *info = &(dev->mdm.info[midx]); - ulong flags; - - save_flags(flags); - cli(); - if (info->xmit_count > 0) { - struct tty_struct *tty = info->tty; + if (USG_MODEMORVOICE(dev->usage[i])) + if ((midx = dev->m_idx[i]) >= 0) { + modem_info *info = &dev->mdm.info[midx]; + if ((info->online > 1) || + (info->vonline ==2 )) { + if (skb_queue_len(info->xmit_buf)) { ton = 1; -#if 0 - printk(KERN_DEBUG "WB2: %d\n", info->xmit_count); -#endif - bufptr = info->xmit_buf; - buflen = info->xmit_count; - if (dev->mdm.atmodem[midx].mdmreg[13] & 2) { - /* Add T.70 simplified header */ -#ifdef ISDN_DEBUG_MODEM_DUMP - isdn_dumppkt("T70pack3:", bufptr, buflen, 40); -#endif - bufptr -= 4; - buflen += 4; - memcpy(bufptr, "\1\0\1\0", 4); -#ifdef ISDN_DEBUG_MODEM_DUMP - isdn_dumppkt("T70pack4:", bufptr, buflen, 40); -#endif - } - if (isdn_writebuf_stub(info->isdn_driver, info->isdn_channel, - bufptr, buflen, 0) > 0) { - info->xmit_count = 0; - info->xmit_size = dev->mdm.atmodem[midx].mdmreg[16] * 16; -#if FUTURE - info->send_outstanding++; - dev->mdm.msr[midx] &= ~UART_MSR_CTS; -#endif - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); - wake_up_interruptible(&tty->write_wait); - } + isdn_tty_senddown(info); } - restore_flags(flags); } + } isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton); } -#if FUTURE /* * A packet has been output successfully. * Search the tty-devices for an appropriate device, decrement its - * counter for outstanding packets, and set CTS if this counter reaches 0. + * counter for outstanding packets, and set CTS. */ void isdn_tty_bsent(int drv, int chan) { @@ -2058,15 +2613,13 @@ void isdn_tty_bsent(int drv, int chan) for (i = 0; i < ISDN_MAX_CHANNELS; i++) { modem_info *info = &dev->mdm.info[i]; if ((info->isdn_driver == drv) && - (info->isdn_channel == chan) && - (info->send_outstanding)) { - if (!(--info->send_outstanding)) - dev->mdm.msr[i] |= UART_MSR_CTS; - restore_flags(flags); - return; - } + (info->isdn_channel == chan) ) { + info->msr |= UART_MSR_CTS; + if (info->send_outstanding) + if (!(--info->send_outstanding)) + info->lsr &= ~UART_LSR_TEMT; + } } restore_flags(flags); return; } -#endif /* FUTURE */ diff --git a/drivers/isdn/isdn_tty.h b/drivers/isdn/isdn_tty.h index e128464fb003..f317d23ae3d2 100644 --- a/drivers/isdn/isdn_tty.h +++ b/drivers/isdn/isdn_tty.h @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.h,v 1.1 1996/01/10 21:39:22 fritz Exp fritz $ +/* $Id: isdn_tty.h,v 1.5 1996/05/17 03:52:31 fritz Exp $ * * header for Linux ISDN subsystem, tty related functions (linklevel). * @@ -20,6 +20,18 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.h,v $ + * Revision 1.5 1996/05/17 03:52:31 fritz + * Changed DLE handling for audio receive. + * + * Revision 1.4 1996/05/11 21:52:34 fritz + * Changed queue management to use sk_buffs. + * + * Revision 1.3 1996/05/07 09:16:34 fritz + * Changed isdn_try_read parameter. + * + * Revision 1.2 1996/04/30 21:05:27 fritz + * Test commit + * * Revision 1.1 1996/01/10 21:39:22 fritz * Initial revision * @@ -32,8 +44,8 @@ extern void isdn_tty_modem_xmit(void); extern void isdn_tty_modem_hup(modem_info *); extern int isdn_tty_modem_init(void); extern void isdn_tty_readmodem(void); -extern int isdn_tty_try_read(int, u_char *, int); +extern int isdn_tty_try_read(modem_info *, struct sk_buff *); extern int isdn_tty_find_icall(int, int, char *); -#if FUTURE +extern int isdn_tty_countDLE(unsigned char *, int); extern void isdn_tty_bsent(int, int); -#endif +extern void isdn_tty_cleanup_xmit(modem_info *); diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index 5e76e6301b55..4f4a3f8d6033 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -52,9 +52,9 @@ static char* pcbit_devname[MAX_PCBIT_CARDS] = { */ int pcbit_command(isdn_ctrl* ctl); -int pcbit_stat(u_char* buf, int len, int user); +int pcbit_stat(u_char* buf, int len, int user, int, int); int pcbit_xmit(int driver, int chan, struct sk_buff *skb); -int pcbit_writecmd(const u_char*, int, int); +int pcbit_writecmd(const u_char*, int, int, int, int); static int set_protocol_running(struct pcbit_dev * dev); @@ -390,19 +390,16 @@ int pcbit_xmit(int driver, int chnum, struct sk_buff *skb) } -int pcbit_writecmd(const u_char* buf, int len, int user) +int pcbit_writecmd(const u_char* buf, int len, int user, int driver, int channel) { struct pcbit_dev * dev; - int board, i, j; + int i, j; const u_char * loadbuf; u_char * ptr = NULL; int errstat; - /* we should have the driver id as input here too - let's say it's 0 */ - board = 0; - - dev = dev_pcbit[board]; + dev = finddev(driver); if (!dev) { @@ -760,7 +757,7 @@ static int stat_end = 0; (flag ? memcpy_tofs(d, s, len) : memcpy(d, s, len)) -int pcbit_stat(u_char* buf, int len, int user) +int pcbit_stat(u_char* buf, int len, int user, int driver, int channel) { int stat_count; stat_count = stat_end - stat_st; diff --git a/drivers/isdn/teles/buffers.c b/drivers/isdn/teles/buffers.c index c747dcb5ffd9..30ed16834822 100644 --- a/drivers/isdn/teles/buffers.c +++ b/drivers/isdn/teles/buffers.c @@ -1,6 +1,9 @@ -/* $Id: buffers.c,v 1.1 1996/04/13 10:19:28 fritz Exp $ +/* $Id: buffers.c,v 1.2 1996/04/29 22:48:14 fritz Exp $ * * $Log: buffers.c,v $ + * Revision 1.2 1996/04/29 22:48:14 fritz + * Removed compatibility-macros. No longer needed. + * * Revision 1.1 1996/04/13 10:19:28 fritz * Initial revision * @@ -47,7 +50,7 @@ BufPoolAdd(struct BufPool *bp, int priority) printk(KERN_DEBUG "BufPoolAdd bp %x\n", bp); #endif - ptr = (struct Pages *) __get_free_pages(priority,bp->pageorder,0); + ptr = (struct Pages *) __get_free_pages(priority, bp->pageorder, 0); if (!ptr) { printk(KERN_WARNING "BufPoolAdd couldn't get pages!\n"); return (-1); diff --git a/drivers/isdn/teles/callc.c b/drivers/isdn/teles/callc.c index 7ed0da48b3c9..3eea3c8a8dd7 100644 --- a/drivers/isdn/teles/callc.c +++ b/drivers/isdn/teles/callc.c @@ -1,6 +1,24 @@ -/* $Id: callc.c,v 1.2 1996/04/20 16:42:29 fritz Exp fritz $ +/* $Id: callc.c,v 1.7 1996/05/17 03:40:37 fritz Exp $ * * $Log: callc.c,v $ + * Revision 1.7 1996/05/17 03:40:37 fritz + * General cleanup. + * + * Revision 1.6 1996/05/10 22:42:07 fritz + * Added entry for EV_RELEASE_CNF in ST_OUT (if no D-Channel avail.) + * + * Revision 1.5 1996/05/06 10:16:15 fritz + * Added voice stuff. + * + * Revision 1.4 1996/04/30 22:04:05 isdn4dev + * improved callback Karsten Keil + * + * Revision 1.3 1996/04/30 10:04:19 fritz + * Started voice support. + * Added printk() to debug-switcher for easier + * synchronization between printk()'s and output + * of /dev/isdnctrl. + * * Revision 1.2 1996/04/20 16:42:29 fritz * Changed statemachine to allow reject of incoming calls. * @@ -43,17 +61,6 @@ stat_debug(struct Channel *chanp, char *s) teles_putstatus(tmp); } -#ifdef DEFINED_BUT_NOT_USED -static void -stat_error(struct Channel *chanp, char *s) -{ - char tmp[100]; - - sprintf(tmp, "Channel %d: %s\n", chanp->chan, s); - teles_putstatus(tmp); -} -#endif - enum { ST_NULL, /* 0 inactive */ ST_OUT, /* 1 outgoing, awaiting SETUP confirm */ @@ -237,6 +244,7 @@ r1(struct FsmInst *fi, int event, void *arg) chanp->lc_b.l2_establish = !0; break; case (ISDN_PROTO_L2_HDLC): + case (ISDN_PROTO_L2_TRANS): chanp->lc_b.l2_establish = 0; break; default: @@ -419,6 +427,7 @@ r9(struct FsmInst *fi, int event, void *arg) chanp->lc_b.l2_establish = !0; break; case (ISDN_PROTO_L2_HDLC): + case (ISDN_PROTO_L2_TRANS): chanp->lc_b.l2_establish = 0; break; default: @@ -467,16 +476,6 @@ r12(struct FsmInst *fi, int event, void *arg) iif.statcallb(&ic); } -#ifdef DEFINED_BUT_NOT_USED -static void -prp(byte * p, int size) -{ - while (size--) - printk("%2x ", *p++); - printk("\n"); -} -#endif - static void r15(struct FsmInst *fi, int event, void *arg) { @@ -664,6 +663,7 @@ static struct FsmNode fnlist[] = {ST_OUT, EV_SETUP_CNF, r10}, {ST_OUT, EV_HANGUP, r2_1}, {ST_OUT, EV_RELEASE_IND, r20}, + {ST_OUT, EV_RELEASE_CNF, r20}, {ST_OUT, EV_DLRL, r2_2}, {ST_OUT_W_HANGUP, EV_RELEASE_IND, r2_2}, {ST_OUT_W_HANGUP, EV_DLRL, r20}, @@ -674,7 +674,7 @@ static struct FsmNode fnlist[] = {ST_IN_W, EV_DLEST, r7}, {ST_IN_W, EV_DLRL, r3_1}, {ST_IN, EV_DLRL, r3_1}, - {ST_IN, EV_HANGUP, r3_1}, + {ST_IN, EV_HANGUP, r2_1}, {ST_IN, EV_RELEASE_IND, r2_2}, {ST_IN, EV_RELEASE_CNF, r2_2}, {ST_IN, EV_ACCEPTD, r8}, @@ -830,6 +830,7 @@ release_ds(int chan) releasestack_isdnl2(st); break; case (ISDN_PROTO_L2_HDLC): + case (ISDN_PROTO_L2_TRANS): releasestack_transl2(st); break; } @@ -1121,22 +1122,13 @@ release_is(int chan) BufQueueRelease(&st->l2.i_queue); } -static void -release_chan(int chan) -{ -#if 0 - release_ds(chan); -#endif - release_is(chan); -} - void CallcFreeChan(void) { int i; for (i = 0; i < chancount; i++) - release_chan(i); + release_is(i); Sfree((void *) chanlist); } @@ -1248,6 +1240,14 @@ init_ds(int chan, int incoming) st->l1.hscxmode = 2; st->l1.hscxchannel = chanlist[chan].para.bchannel - 1; break; + case (ISDN_PROTO_L2_TRANS): + st->l1.l1l2 = lltrans_handler; + st->l1.l1man = dcc_l1man; + st->l4.userdata = chanlist + chan; + st->l4.l1writewakeup = ll_writewakeup; + st->l1.hscxmode = 1; + st->l1.hscxchannel = chanlist[chan].para.bchannel - 1; + break; } return (0); @@ -1345,6 +1345,7 @@ teles_command(isdn_ctrl * ic) distr_debug(); sprintf(tmp, "debugging flags set to %x\n", debugflags); teles_putstatus(tmp); + printk(KERN_DEBUG "%s", tmp); break; case (2): num = *(unsigned int *) ic->num; diff --git a/drivers/isdn/teles/card.c b/drivers/isdn/teles/card.c index 3eb297c4a730..d7787f32eae7 100644 --- a/drivers/isdn/teles/card.c +++ b/drivers/isdn/teles/card.c @@ -1,4 +1,4 @@ -/* $Id: card.c,v 1.1 1996/04/13 10:22:42 fritz Exp $ +/* $Id: card.c,v 1.5 1996/05/17 03:45:02 fritz Exp $ * * card.c low level stuff for the Teles S0 isdn card * @@ -7,6 +7,28 @@ * Beat Doebeli log all D channel traffic * * $Log: card.c,v $ + * Revision 1.5 1996/05/17 03:45:02 fritz + * Made error messages more clearly. + * Bugfix: Only 31 bytes of 32-byte audio frames + * have been transfered to upper layers. + * + * Revision 1.4 1996/05/06 10:17:57 fritz + * Added voice-send stuff + * (Not reporting EXIR when in voice-mode, since it's normal). + * + * Revision 1.3 1996/04/30 22:02:40 isdn4dev + * Bugfixes for 16.3 + * -improved IO allocation + * -fix second B channel problem + * -correct ph_command patch + * + * Revision 1.2 1996/04/30 10:00:59 fritz + * Bugfix: Added ph_command(8) for 16.3. + * Bugfix: Ports did not get registered correctly + * when using a 16.3. + * Started voice support. + * Some experimental changes of waitforXFW(). + * * Revision 1.1 1996/04/13 10:22:42 fritz * Initial revision * @@ -21,6 +43,7 @@ #include #undef DCHAN_VERBOSE +#define FRITZ_EXPERIMENTAL extern void tei_handler(struct PStack *st, byte pr, struct BufHeader *ibh); @@ -183,11 +206,16 @@ waitforCEC_3(int iobase, byte hscx) static inline void waitforXFW_0(byte * base, byte hscx) { +#ifdef FRITZ_EXPERIMENTAL + long to = 20; + + while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x44)==0x40) && to) { +#else long to = 10; waitforCEC_0(base, hscx); - while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x40)) && to) { +#endif udelay(5); to--; } @@ -198,11 +226,16 @@ waitforXFW_0(byte * base, byte hscx) static inline void waitforXFW_3(int iobase, byte hscx) { +#ifdef FRITZ_EXPERIMENTAL + long to = 20; + + while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x44)==0x40) && to) { +#else long to = 10; waitforCEC_3(iobase, hscx); - while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x40)) && to) { +#endif udelay(5); to--; } @@ -332,15 +365,6 @@ hscx_empty_fifo(struct HscxState *hsp, int count) readhscx_s(hsp->iobase, hsp->hscx, 0x3e, ptr, count); writehscxCMDR_3(hsp->iobase, hsp->hscx, 0x80); } -#ifdef BCHAN_VERBOSE - { - int i; - printk(KERN_DEBUG "hscx_empty_fifo"); - for (i = 0; i < count; i++) - printk(" %2x", ptr[i]); - printk("\n"); - } -#endif /* BCHAN_VERBOSE */ } static void @@ -361,15 +385,7 @@ hscx_fill_fifo(struct HscxState *hsp) if (count <= 0) return; -#if 0 - if (!hsp->sendptr) { - ptr = DATAPTR(ibh); - printk(KERN_DEBUG "snd bytes %2x %2x %2x %2x %2x\n", ptr[0], ptr[1], ptr[2], - ptr[3], ptr[4]); - } -#endif - - more = 0; + more = (hsp->mode == 1)?1:0; if (count > 32) { more = !0; count = 32; @@ -417,7 +433,7 @@ hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) printk(KERN_WARNING "Teles: HSCX invalid frame\n"); if (r & 0x40) - printk(KERN_WARNING "Teles: HSCX RDO\n"); + printk(KERN_WARNING "Teles: HSCX RDO mode=%d\n",hsp->mode); if (!r & 0x20) printk(KERN_WARNING "Teles: HSCX CRC error\n"); if (hsp->rcvibh) @@ -455,7 +471,7 @@ hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool, GFP_ATOMIC, (void *) 1, 2)) { printk(KERN_WARNING - "HSCX RME out of buffers at %ld\n", + "HSCX RPF out of buffers at %ld\n", jiffies); WRITEHSCX_CMDR(hsp->membase, hsp->iobase, hsp->hscx, 0x80); @@ -464,12 +480,14 @@ hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) hsp->rcvptr = 0; hscx_empty_fifo(hsp, 32); -#ifdef VOICE - hsp->rcvibh->datasize = hsp->rcvptr - 1; - BufQueueLink(&hsp->rq, hsp->rcvibh); - hsp->rcvibh = NULL; - hscx_sched_event(hsp, HSCX_RCVBUFREADY); -#endif + if (hsp->mode == 1) { + /* receive audio data */ + hsp->rcvibh->datasize = hsp->rcvptr; + BufQueueLink(&hsp->rq, hsp->rcvibh); + hsp->rcvibh = NULL; + hscx_sched_event(hsp, HSCX_RCVBUFREADY); + } + } afterRPF: if (val & 0x10) { /* XPR */ @@ -651,8 +669,17 @@ isac_new_ph(struct IsdnCardState *sp) ph_command(sp, 9); break; case (12): + ph_command(sp, 8); + sp->ph_active = 5; + isac_sched_event(sp, ISAC_PHCHANGE); + if (!sp->xmtibh) + if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) + sp->sendptr = 0; + if (sp->xmtibh) + fill_fifo(sp); + break; case (13): - ph_command(sp, 8); + ph_command(sp, 9); sp->ph_active = 5; isac_sched_event(sp, ISAC_PHCHANGE); if (!sp->xmtibh) @@ -673,7 +700,7 @@ isac_new_ph(struct IsdnCardState *sp) static void teles_interrupt(int intno, void *dev_id, struct pt_regs *regs) { - byte val, val2, r; + byte val, val2, r, exval; struct IsdnCardState *sp; unsigned int count; struct HscxState *hsp; @@ -688,10 +715,12 @@ teles_interrupt(int intno, void *dev_id, struct pt_regs *regs) if (val & 0x01) { hsp = sp->hs + 1; - printk(KERN_WARNING "HSCX B EXIR %x xmitbh %lx rcvibh %lx\n", - READHSCX(sp->membase, sp->iobase, 1, HSCX_EXIR), - (long) hsp->xmtibh, - (long) hsp->rcvibh); + exval = READHSCX(sp->membase, sp->iobase, 1, HSCX_EXIR); + if ((hsp->mode == 1) || (exval == 0x40)) + hscx_fill_fifo(hsp); + else + printk(KERN_WARNING "HSCX B EXIR %x xmitbh %lx rcvibh %lx\n", + exval, (long) hsp->xmtibh, (long) hsp->rcvibh); } if (val & 0xf8) { if (sp->debug) @@ -699,8 +728,12 @@ teles_interrupt(int intno, void *dev_id, struct pt_regs *regs) hscx_interrupt(sp, val, 1); } if (val & 0x02) { - printk(KERN_WARNING "HSCX A EXIR %x\n", - READHSCX(sp->membase, sp->iobase, 0, HSCX_EXIR)); + hsp = sp->hs; + exval = READHSCX(sp->membase, sp->iobase, 0, HSCX_EXIR); + if ((hsp->mode == 1) && (exval == 0x40)) + hscx_fill_fifo(hsp); + else + printk(KERN_WARNING "HSCX A EXIR %x\n",exval); } /* ??? Why do that vvvvvvvvvvvvvvvvvvvvv different on Teles 16-3 ??? */ @@ -1057,17 +1090,46 @@ checkcard(int cardnr) case 0x180: case 0x280: case 0x380: - printk(KERN_INFO "teles: port 0x%x specified, assuming 0x%x\n", - card->iobase, (card->iobase | 0xc00)); card->iobase |= 0xc00; break; } - if (check_region(card->iobase, 8)) { - printk(KERN_WARNING - "teles: ports %x-%x already in use\n", - card->iobase, - card->iobase + 8 ); - return -1; + if (card->membase) { /* 16.0 */ + if (check_region(card->iobase, 8)) { + printk(KERN_WARNING + "teles: ports %x-%x already in use\n", + card->iobase, + card->iobase + 8 ); + return -1; + } + } else { /* 16.3 */ + if (check_region(card->iobase, 16)) { + printk(KERN_WARNING + "teles: 16.3 ports %x-%x already in use\n", + card->iobase, + card->iobase + 16 ); + return -1; + } + if (check_region((card->iobase - 0xc00) , 32)) { + printk(KERN_WARNING + "teles: 16.3 ports %x-%x already in use\n", + card->iobase - 0xc00, + card->iobase - 0xc00 + 32); + return -1; + } + if (check_region((card->iobase - 0x800) , 32)) { + printk(KERN_WARNING + "teles: 16.3 ports %x-%x already in use\n", + card->iobase - 0x800, + card->iobase - 0x800 + 32); + return -1; + } + if (check_region((card->iobase - 0x400) , 32)) { + printk(KERN_WARNING + "teles: 16.3 ports %x-%x already in use\n", + card->iobase - 0x400, + card->iobase - 0x400 + 32); + return -1; + } } switch (card->interrupt) { case 2: @@ -1100,30 +1162,37 @@ checkcard(int cardnr) } if (card->membase) { cfval |= (((unsigned int) card->membase >> 9) & 0xF0); - - if (bytein(card->iobase + 0) != 0x51) { - printk(KERN_INFO "XXX Byte at %x is %x\n", - card->iobase + 0, - bytein(card->iobase + 0)); - return -2; - } - if (bytein(card->iobase + 1) != 0x93) { - printk(KERN_INFO "XXX Byte at %x is %x\n", - card->iobase + 1, - bytein(card->iobase + 1)); - return -2; - } - val = bytein(card->iobase + 2); /* 0x1e=without AB - * 0x1f=with AB - */ - if (val != 0x1e && val != 0x1f) { - printk(KERN_INFO "XXX Byte at %x is %x\n", - card->iobase + 2, - bytein(card->iobase + 2)); - return -2; - } + } + if (bytein(card->iobase + 0) != 0x51) { + printk(KERN_INFO "XXX Byte at %x is %x\n", + card->iobase + 0, + bytein(card->iobase + 0)); + return -2; + } + if (bytein(card->iobase + 1) != 0x93) { + printk(KERN_INFO "XXX Byte at %x is %x\n", + card->iobase + 1, + bytein(card->iobase + 1)); + return -2; + } + val = bytein(card->iobase + 2); /* 0x1e=without AB + * 0x1f=with AB + * 0x1c 16.3 ??? + */ + if (val != 0x1c && val != 0x1e && val != 0x1f) { + printk(KERN_INFO "XXX Byte at %x is %x\n", + card->iobase + 2, + bytein(card->iobase + 2)); + return -2; + } + if (card->membase) { /* 16.0 */ + request_region(card->iobase, 8, "teles 16.0"); + } else { + request_region(card->iobase, 16, "teles 16.3"); + request_region(card->iobase - 0xC00, 32, "teles HSCX0"); + request_region(card->iobase - 0x800, 32, "teles HSCX1"); + request_region(card->iobase - 0x400, 32, "teles ISAC"); } - request_region(card->iobase, 8, "teles"); cli(); timout = jiffies + (HZ / 10) + 1; byteout(card->iobase + 4, cfval); @@ -1182,10 +1251,11 @@ modehscx(struct HscxState *hs, int mode, printk(KERN_DEBUG "modehscx hscx %d mode %d ichan %d\n", hscx, mode, ichan); - if (hscx == 0) - ichan = 1 - ichan; /* raar maar waar... */ - + hs->mode = mode; if (sp->membase) { + /* What's that ??? KKeil */ + if (hscx == 0) + ichan = 1 - ichan; /* raar maar waar... */ writehscx_0(sp->membase, hscx, HSCX_CCR1, 0x85); writehscx_0(sp->membase, hscx, HSCX_XAD1, 0xFF); writehscx_0(sp->membase, hscx, HSCX_XAD2, 0xFF); @@ -1547,7 +1617,7 @@ get_irq(int cardnr) static void release_irq(int cardnr) { - struct IsdnCard *card = cards + cardnr; + struct IsdnCard *card = cards + cardnr; irq2dev_map[card->interrupt] = NULL; free_irq(card->interrupt, NULL); @@ -1584,7 +1654,14 @@ closecard(int cardnr) close_hscxstate(sp->hs); if (cards[cardnr].iobase) - release_region(cards[cardnr].iobase, 8); + if (cards[cardnr].membase) { /* 16.0 */ + release_region(cards[cardnr].iobase, 8); + } else { + release_region(cards[cardnr].iobase, 16); + release_region(cards[cardnr].iobase - 0xC00, 32); + release_region(cards[cardnr].iobase - 0x800, 32); + release_region(cards[cardnr].iobase - 0x400, 32); + } Sfree((void *) sp); } @@ -1652,35 +1729,35 @@ hscx_l2l1(struct PStack *st, int pr, struct HscxState *hsp = sp->hs + st->l1.hscx; switch (pr) { - case (PH_DATA): - if (hsp->xmtibh) - BufQueueLink(&hsp->sq, ibh); - else { - hsp->xmtibh = ibh; - hsp->sendptr = 0; - hsp->releasebuf = !0; - hscx_fill_fifo(hsp); - } - break; - case (PH_DATA_PULLED): - if (hsp->xmtibh) { - printk(KERN_DEBUG "hscx_l2l1: this shouldn't happen\n"); - break; - } - hsp->xmtibh = ibh; - hsp->sendptr = 0; - hsp->releasebuf = 0; - hscx_fill_fifo(hsp); - break; - case (PH_REQUEST_PULL): - if (!hsp->xmtibh) { - st->l1.requestpull = 0; - st->l1.l1l2(st, PH_PULL_ACK, NULL); - } else - st->l1.requestpull = !0; - break; + case (PH_DATA): + if (hsp->xmtibh) + BufQueueLink(&hsp->sq, ibh); + else { + hsp->xmtibh = ibh; + hsp->sendptr = 0; + hsp->releasebuf = !0; + hscx_fill_fifo(hsp); + } + break; + case (PH_DATA_PULLED): + if (hsp->xmtibh) { + printk(KERN_DEBUG "hscx_l2l1: this shouldn't happen\n"); + break; + } + hsp->xmtibh = ibh; + hsp->sendptr = 0; + hsp->releasebuf = 0; + hscx_fill_fifo(hsp); + break; + case (PH_REQUEST_PULL): + if (!hsp->xmtibh) { + st->l1.requestpull = 0; + st->l1.l1l2(st, PH_PULL_ACK, NULL); + } else + st->l1.requestpull = !0; + break; } - + } extern struct IsdnBuffers *tracebuf; @@ -1778,7 +1855,5 @@ setstack_hscx(struct PStack *st, struct HscxState *hs) void teles_reportcard(int cardnr) { - printk(KERN_DEBUG "teles_reportcard\n"); - } diff --git a/drivers/isdn/teles/fsm.c b/drivers/isdn/teles/fsm.c index b75cd9bcf4f0..c0b2f494bf94 100644 --- a/drivers/isdn/teles/fsm.c +++ b/drivers/isdn/teles/fsm.c @@ -1,6 +1,9 @@ -/* $Id: fsm.c,v 1.1 1996/04/13 10:23:41 fritz Exp $ +/* $Id: fsm.c,v 1.2 1996/04/29 22:49:57 fritz Exp $ * * $Log: fsm.c,v $ + * Revision 1.2 1996/04/29 22:49:57 fritz + * Removed compatibility-macros. + * * Revision 1.1 1996/04/13 10:23:41 fritz * Initial revision * diff --git a/drivers/isdn/teles/isdnl2.c b/drivers/isdn/teles/isdnl2.c index 6beaf2fab112..779b7b70ac7a 100644 --- a/drivers/isdn/teles/isdnl2.c +++ b/drivers/isdn/teles/isdnl2.c @@ -1,6 +1,9 @@ -/* $Id: isdnl2.c,v 1.1 1996/04/13 10:24:16 fritz Exp $ +/* $Id: isdnl2.c,v 1.2 1996/05/17 03:46:15 fritz Exp $ * * $Log: isdnl2.c,v $ + * Revision 1.2 1996/05/17 03:46:15 fritz + * General cleanup. + * * Revision 1.1 1996/04/13 10:24:16 fritz * Initial revision * @@ -16,43 +19,6 @@ static void l2m_debug(struct FsmInst *fi, char *s); struct Fsm l2fsm = {NULL, 0, 0}; -#if 0 - - -enum { - ST_PH_NULL, - ST_PH_ACTIVATED, - ST_PH_ACTIVE, -}; - -#define PH_STATE_COUNT (ST_PH_ACTIVE+1) - -static char *strPhState[] = -{ - "ST_PH_NULL", - "ST_PH_ACTIVATED", - "ST_PH_ACTIVE", -}; - -enum { - EV_PH_ACTIVATE_REQ, - EV_PH_ACTIVATE, - EV_PH_DEACTIVATE_REQ, - EV_PH_DEACTIVATE, -}; - -#define PH_EVENT_COUNT (EV_PH_DEACTIVATE+1) - -static char *strPhEvent[] = -{ - "EV_PH_ACTIVATE_REQ", - "EV_PH_ACTIVATE", - "EV_PH_DEACTIVATE_REQ", - "EV_PH_DEACTIVATE", -}; - -#endif - enum { ST_L2_1, ST_L2_3, @@ -121,54 +87,6 @@ static char *strL2Event[] = "EV_L2_RNR", }; -#if 0 -static void -ph_r1(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_PH_ACTIVATED); - st->l1.service_down(st, PH_ACTIVATE, NULL); -} - -static void -ph_r2(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_PH_ACTIVE); - st->l3.service_up(st, DL_ACTIVATE_CNF, NULL); -} - -static void -ph_r3(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_PH_NULL); - st->l1.service_down(st, PH_DEACTIVATE, NULL); -} - -static void -ph_r4(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_PH_NULL); - st->l3.service_up(st, DL_DEACTIVATE_IND, NULL); -} - -static struct FsmNode PhFnList[] = -{ - {ST_PH_NULL, EV_PH_ACTIVATE_REQ, ph_r1}, - {ST_PH_ACTIVATED, EV_PH_ACTIVATE, ph_r2}, - {ST_PH_ACTIVATED, EV_PH_DEACTIVATE, ph_r4}, - {ST_PH_ACTIVE, EV_PH_DEACTIVATE_REQ, ph_r3}, -}; - -#define PH_FN_COUNT (sizeof(PhFnList)/sizeof(struct FsmNode)) -#endif - int errcount = 0; static int l2addrsize(struct Layer2 *tsp); @@ -191,27 +109,6 @@ discard_i_queue(struct PStack *st) BufPoolRelease(ibh); } -#ifdef DEFINED_BUT_NOT_USED -static void -discard_window(struct PStack *st) -{ - struct BufHeader *ibh; - struct Layer2 *l2; - int i, p1, p2; - - l2 = &st->l2; - p1 = l2->vs - l2->va; - if (p1 < 0) - p1 += l2->extended ? 128 : 8; - - for (i = 0; i < p1; i++) { - p2 = (i + l2->sow) % l2->window; - ibh = l2->windowar[p2]; - BufPoolRelease(ibh); - } -} -#endif - int l2headersize(struct Layer2 *tsp, int UI) { @@ -254,12 +151,6 @@ static void enqueue_ui(struct PStack *st, struct BufHeader *ibh) { -#ifdef FRITZDEBUG - static char tmp[100]; - - sprintf(tmp, "enqueue_ui: %d bytes\n", ibh->datasize); - teles_putstatus(tmp); -#endif st->l2.l2l1(st, PH_DATA, ibh); } @@ -267,12 +158,6 @@ static void enqueue_super(struct PStack *st, struct BufHeader *ibh) { -#ifdef FRITZDEBUG - static char tmp[100]; - - sprintf(tmp, "enqueue_super: %d bytes\n", ibh->datasize); - teles_putstatus(tmp); -#endif st->l2.l2l1(st, PH_DATA, ibh); } @@ -1405,36 +1290,9 @@ setstack_isdnl2(struct PStack *st, char *debug_id) st->l2.t200_running = 0; } -#ifdef DEFINED_BUT_NOT_USED -static void -trans_acceptph(struct PStack *st, struct BufHeader *ibh) -{ -#if 0 - st->l3.service_up(st, DL_DATA, ibh); -#endif -} - - -static void -transdown(struct PStack *st, int pr, - struct BufHeader *ibh) -{ - if (pr == DL_DATA) { - ibh->primitive = !0; - st->l2.l2l1(st, PH_DATA, ibh); - } -} -#endif - void setstack_transl2(struct PStack *st) { -#if 0 - st->l2.phdata_up = trans_acceptph; - st->l2.service_down = (void *) transdown; - st->l2.ihsize = 0; - st->l2.debug = 0; -#endif } void diff --git a/drivers/isdn/teles/isdnl3.c b/drivers/isdn/teles/isdnl3.c index b4088d14b60c..6b93bfe71f1f 100644 --- a/drivers/isdn/teles/isdnl3.c +++ b/drivers/isdn/teles/isdnl3.c @@ -1,6 +1,16 @@ -/* $Id: isdnl3.c,v 1.2 1996/04/20 16:45:05 fritz Exp $ +/* $Id: isdnl3.c,v 1.5 1996/05/18 01:37:16 fritz Exp $ * * $Log: isdnl3.c,v $ + * Revision 1.5 1996/05/18 01:37:16 fritz + * Added spelling corrections and some minor changes + * to stay in sync with kernel. + * + * Revision 1.4 1996/05/17 03:46:16 fritz + * General cleanup. + * + * Revision 1.3 1996/04/30 21:57:53 isdn4dev + * remove some debugging code, improve callback Karsten Keil + * * Revision 1.2 1996/04/20 16:45:05 fritz * Changed to report all incoming calls to Linklevel, not just those * with Service 7. @@ -123,17 +133,9 @@ l3s5(struct PStack *st, byte pr, *p++ = 0x90; /* Packet-Mode 64kbps */ break; } -/* - * What about info2? Mapping to High-Layer-Compatibility? - */ - -#if 0 /* user-user not allowed in The Netherlands! */ - *p++ = 0x7f; - *p++ = 0x2; - *p++ = 0x0; - *p++ = 66; -#endif - + /* + * What about info2? Mapping to High-Layer-Compatibility? + */ if (st->pa->calling[0] != '\0') { *p++ = 0x6c; *p++ = strlen(st->pa->calling) + 1; @@ -308,15 +310,6 @@ l3s13(struct PStack *st, byte pr, void *arg) newl3state(st, 0); } -#ifdef DEFINED_BUT_NOT_USED -static void -l3s15(struct PStack *st, byte pr, void *arg) -{ - newl3state(st, 0); - st->l3.l3l4(st, CC_REJECT, NULL); -} -#endif - static void l3s16(struct PStack *st, byte pr, void *arg) @@ -475,11 +468,6 @@ l3up(struct PStack *st, ptr = DATAPTR(ibh); ptr += st->l2.ihsize; size = ibh->datasize - st->l2.ihsize; - if (DEBUG_1TR6 > 6) { - printk(KERN_INFO "isdnl3/l3up DL_DATA size=%d\n", size); - for (i = 0; i < size; i++) - printk(KERN_INFO "l3up data %x\n", ptr[i]); - } mt = ptr[3]; switch (ptr[0]) { #ifdef P_1TR6 @@ -494,8 +482,8 @@ l3up(struct PStack *st, if (i == datasl_1tr6t_len) { BufPoolRelease(ibh); if (DEBUG_1TR6 > 0) - printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %s\n", - st->l3.state, mt_trans(PROTO_DIS_N1, mt)); + printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %x\n", + st->l3.state, mt); } else datastatelist_1tr6t[i].rout(st, pr, ibh); break; @@ -507,6 +495,9 @@ l3up(struct PStack *st, break; if (i == datasllen) { BufPoolRelease(ibh); + if (DEBUG_1TR6 > 0) + printk(KERN_INFO "isdnl3up unhandled E-DSS1 state %d MT %x\n", + st->l3.state, mt); } else datastatelist[i].rout(st, pr, ibh); } @@ -514,11 +505,6 @@ l3up(struct PStack *st, ptr = DATAPTR(ibh); ptr += st->l2.uihsize; size = ibh->datasize - st->l2.uihsize; - if (DEBUG_1TR6 > 6) { - printk(KERN_INFO "isdnl3/l3up DL_UNIT_DATA size=%d\n", size); - for (i = 0; i < size; i++) - printk(KERN_INFO "l3up data %x\n", ptr[i]); - } mt = ptr[3]; switch (ptr[0]) { #ifdef P_1TR6 @@ -532,8 +518,8 @@ l3up(struct PStack *st, break; if (i == datasl_1tr6t_len) { if (DEBUG_1TR6 > 0) { - printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %s\n" - ,st->l3.state, mt_trans(PROTO_DIS_N1, mt)); + printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %x\n" + ,st->l3.state, mt); } BufPoolRelease(ibh); } else @@ -547,6 +533,9 @@ l3up(struct PStack *st, break; if (i == datasllen) { BufPoolRelease(ibh); + if (DEBUG_1TR6 > 0) + printk(KERN_INFO "isdnl3up unhandled E-DSS1 state %d MT %x\n", + st->l3.state, mt); } else datastatelist[i].rout(st, pr, ibh); } @@ -581,6 +570,9 @@ l3down(struct PStack *st, (pr == downstatelist[i].primitive)) break; if (i == downsllen) { + if (DEBUG_1TR6 > 0) { + printk(KERN_INFO "isdnl3down unhandled E-DSS1 state %d primitiv %x\n", st->l3.state, pr); + } } else downstatelist[i].rout(st, pr, ibh); } diff --git a/drivers/isdn/teles/l3_1TR6.c b/drivers/isdn/teles/l3_1TR6.c index 71568e7ab43c..a451eed2a42f 100644 --- a/drivers/isdn/teles/l3_1TR6.c +++ b/drivers/isdn/teles/l3_1TR6.c @@ -1,6 +1,9 @@ -/* $Id: l3_1TR6.c,v 1.2 1996/04/20 16:47:23 fritz Exp $ +/* $Id: l3_1TR6.c,v 1.3 1996/04/30 21:54:42 isdn4dev Exp $ * * $Log: l3_1TR6.c,v $ + * Revision 1.3 1996/04/30 21:54:42 isdn4dev + * SPV, callback , remove some debugging code Karsten Keil + * * Revision 1.2 1996/04/20 16:47:23 fritz * Changed statemachine to allow reject of an incoming call. * Report all incoming calls, not just those with Service = 7. @@ -12,27 +15,6 @@ * */ -char * -mt_trans(int pd, int mt) -{ - int i; - - if (pd == PROTO_DIS_N0) { - for (i = 0; i < (sizeof(mtdesc_n0) / sizeof(struct MTypeDesc)); i++) { - if (mt == mtdesc_n0[i].mt) - return (mtdesc_n0[i].descr); - } - return ("unknown Message Type PD=N0"); - } else if (pd == PROTO_DIS_N1) { - for (i = 0; i < (sizeof(mtdesc_n1) / sizeof(struct MTypeDesc)); i++) { - if (mt == mtdesc_n1[i].mt) - return (mtdesc_n1[i].descr); - } - return ("unknown Message Type PD=N1"); - } - return ("unknown Protokolldiscriminator"); -} - static void l3_1TR6_message(struct PStack *st, int mt, int pd) { @@ -59,10 +41,6 @@ l3_1tr6_setup(struct PStack *st, byte pr, void *arg) byte *p; char *teln; -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: sent SETUP\n"); -#endif - st->l3.callref = st->pa->callref; BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19); p = DATAPTR(dibh); @@ -73,7 +51,21 @@ l3_1tr6_setup(struct PStack *st, byte pr, void *arg) *p++ = st->l3.callref; *p++ = MT_N1_SETUP; - + if ('S' == (st->pa->called[0] & 0x5f)) { /* SPV ??? */ + /* NSF SPV */ + *p++ = WE0_netSpecFac; + *p++ = 4; /* Laenge */ + *p++ = 0; + *p++ = FAC_SPV; /* SPV */ + *p++ = st->pa->info; /* 0 for all Services */ + *p++ = st->pa->info2; /* 0 for all Services */ + *p++ = WE0_netSpecFac; + *p++ = 4; /* Laenge */ + *p++ = 0; + *p++ = FAC_Activate; /* aktiviere SPV (default) */ + *p++ = st->pa->info; /* 0 for all Services */ + *p++ = st->pa->info2; /* 0 for all Services */ + } if (st->pa->calling[0] != '\0') { *p++ = WE0_origAddr; *p++ = strlen(st->pa->calling) + 1; @@ -84,11 +76,17 @@ l3_1tr6_setup(struct PStack *st, byte pr, void *arg) *p++ = *teln++ & 0x7f; } *p++ = WE0_destAddr; - *p++ = strlen(st->pa->called) + 1; + teln = st->pa->called; + if ('S' != (st->pa->called[0] & 0x5f)) { /* Keine SPV ??? */ + *p++ = strlen(st->pa->called) + 1; + st->pa->spv = 0; + } else { /* SPV */ + *p++ = strlen(st->pa->called); + teln++; /* skip S */ + st->pa->spv = 1; + } /* Classify as AnyPref. */ *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - - teln = st->pa->called; while (*teln) *p++ = *teln++ & 0x7f; @@ -106,7 +104,6 @@ l3_1tr6_setup(struct PStack *st, byte pr, void *arg) } - static void l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg) { @@ -118,13 +115,7 @@ l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg) st->pa->callref = getcallref(p); st->l3.callref = 0x80 + st->pa->callref; -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: TU_SETUP cr=%d\n",st->l3.callref); -#endif - - /* - * Channel Identification - */ + /* Channel Identification */ p = DATAPTR(ibh); if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, WE0_chanID, 0))) { @@ -154,6 +145,13 @@ l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg) } else strcpy(st->pa->calling, ""); + p = DATAPTR(ibh); + st->pa->spv = 0; + if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, + WE0_netSpecFac, 0))) { + if ((FAC_SPV == p[3]) || (FAC_Activate == p[3])) + st->pa->spv = 1; + } BufPoolRelease(ibh); /* Signal all services, linklevel takes care of Service-Indicator */ @@ -172,10 +170,6 @@ l3_1tr6_tu_setup_ack(struct PStack *st, byte pr, void *arg) byte *p; struct BufHeader *ibh = arg; -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: SETUP_ACK\n"); -#endif - p = DATAPTR(ibh); if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, WE0_chanID, 0))) { @@ -183,6 +177,7 @@ l3_1tr6_tu_setup_ack(struct PStack *st, byte pr, void *arg) } else printk(KERN_INFO "octect 3 not found\n"); + BufPoolRelease(ibh); newl3state(st, 2); } @@ -193,10 +188,6 @@ l3_1tr6_tu_call_sent(struct PStack *st, byte pr, void *arg) byte *p; struct BufHeader *ibh = arg; -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: CALL_SENT\n"); -#endif - p = DATAPTR(ibh); if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, WE0_chanID, 0))) { @@ -215,9 +206,6 @@ l3_1tr6_tu_alert(struct PStack *st, byte pr, void *arg) byte *p; struct BufHeader *ibh = arg; -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: TU_ALERT\n"); -#endif p = DATAPTR(ibh); if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, @@ -236,24 +224,22 @@ static void l3_1tr6_tu_info(struct PStack *st, byte pr, void *arg) { byte *p; - int i; + int i,tmpcharge=0; char a_charge[8]; struct BufHeader *ibh = arg; -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: TU_INFO\n"); -#endif - p = DATAPTR(ibh); if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, WE6_chargingInfo, 6))) { iecpy(a_charge, p, 1); - st->pa->chargeinfo = 0; - for (i = 0; i < strlen(a_charge); i++) { - st->pa->chargeinfo *= 10; - st->pa->chargeinfo += a_charge[i] & 0xf; - st->l3.l3l4(st, CC_INFO_CHARGE, NULL); - } + for (i = 0; i < strlen (a_charge); i++) { + tmpcharge *= 10; + tmpcharge += a_charge[i] & 0xf; + } + if (tmpcharge > st->pa->chargeinfo) { + st->pa->chargeinfo = tmpcharge; + st->l3.l3l4 (st, CC_INFO_CHARGE, NULL); + } if (DEBUG_1TR6 > 2) printk(KERN_INFO "chargingInfo %d\n", st->pa->chargeinfo); } else if (DEBUG_1TR6 > 2) @@ -269,10 +255,6 @@ l3_1tr6_tu_info_s2(struct PStack *st, byte pr, void *arg) int i; struct BufHeader *ibh = arg; -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: TU_INFO 2\n"); -#endif - if (DEBUG_1TR6 > 4) { p = DATAPTR(ibh); for (i = 0; i < ibh->datasize; i++) { @@ -287,10 +269,7 @@ l3_1tr6_tu_connect(struct PStack *st, byte pr, void *arg) { struct BufHeader *ibh = arg; -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: CONNECT\n"); -#endif - + st->pa->chargeinfo=0; BufPoolRelease(ibh); st->l3.l3l4(st, CC_SETUP_CNF, NULL); newl3state(st, 10); @@ -301,11 +280,6 @@ l3_1tr6_tu_rel(struct PStack *st, byte pr, void *arg) { struct BufHeader *ibh = arg; -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: REL\n"); -#endif - - BufPoolRelease(ibh); l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1); st->l3.l3l4(st, CC_RELEASE_IND, NULL); @@ -317,11 +291,6 @@ l3_1tr6_tu_rel_ack(struct PStack *st, byte pr, void *arg) { struct BufHeader *ibh = arg; -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: REL_ACK\n"); -#endif - - BufPoolRelease(ibh); newl3state(st, 0); st->l3.l3l4(st, CC_RELEASE_CNF, NULL); @@ -332,25 +301,21 @@ l3_1tr6_tu_disc(struct PStack *st, byte pr, void *arg) { struct BufHeader *ibh = arg; byte *p; - int i; + int i,tmpcharge=0; char a_charge[8]; - -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: TU_DISC\n"); -#endif - - p = DATAPTR(ibh); if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, WE6_chargingInfo, 6))) { iecpy(a_charge, p, 1); - st->pa->chargeinfo = 0; - for (i = 0; i < strlen(a_charge); i++) { - st->pa->chargeinfo *= 10; - st->pa->chargeinfo += a_charge[i] & 0xf; - st->l3.l3l4(st, CC_INFO_CHARGE, NULL); - } + for (i = 0; i < strlen (a_charge); i++) { + tmpcharge *= 10; + tmpcharge += a_charge[i] & 0xf; + } + if (tmpcharge > st->pa->chargeinfo) { + st->pa->chargeinfo = tmpcharge; + st->l3.l3l4 (st, CC_INFO_CHARGE, NULL); + } if (DEBUG_1TR6 > 2) printk(KERN_INFO "chargingInfo %d\n", st->pa->chargeinfo); } else if (DEBUG_1TR6 > 2) @@ -380,12 +345,8 @@ l3_1tr6_tu_connect_ack(struct PStack *st, byte pr, void *arg) { struct BufHeader *ibh = arg; -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: CONN_ACK\n"); -#endif - - BufPoolRelease(ibh); + st->pa->chargeinfo = 0; st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL); newl3state(st, 10); } @@ -394,10 +355,6 @@ static void l3_1tr6_alert(struct PStack *st, byte pr, void *arg) { -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: send ALERT\n"); -#endif - l3_1TR6_message(st, MT_N1_ALERT, PROTO_DIS_N1); newl3state(st, 7); } @@ -406,22 +363,45 @@ static void l3_1tr6_conn(struct PStack *st, byte pr, void *arg) { -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: send CONNECT\n"); -#endif + struct BufHeader *dibh; + byte *p; st->l3.callref = 0x80 + st->pa->callref; - l3_1TR6_message(st, MT_N1_CONN, PROTO_DIS_N1); + + BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20); + p = DATAPTR(dibh); + p += st->l2.ihsize; + + *p++ = PROTO_DIS_N1; + *p++ = 0x1; + *p++ = st->l3.callref; + *p++ = MT_N1_CONN; + + if (st->pa->spv) { /* SPV ??? */ + /* NSF SPV */ + *p++ = WE0_netSpecFac; + *p++ = 4; /* Laenge */ + *p++ = 0; + *p++ = FAC_SPV; /* SPV */ + *p++ = st->pa->info; + *p++ = st->pa->info2; + *p++ = WE0_netSpecFac; + *p++ = 4; /* Laenge */ + *p++ = 0; + *p++ = FAC_Activate; /* aktiviere SPV */ + *p++ = st->pa->info; + *p++ = st->pa->info2; + } + dibh->datasize = p - DATAPTR(dibh); + + i_down(st, dibh); + newl3state(st, 8); } static void l3_1tr6_ignore(struct PStack *st, byte pr, void *arg) { -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: IGNORE\n"); -#endif - newl3state(st, 0); } @@ -432,10 +412,6 @@ l3_1tr6_disconn_req(struct PStack *st, byte pr, void *arg) byte *p; byte rejflg; -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: send DISCON\n"); -#endif - BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 21); p = DATAPTR(dibh); p += st->l2.ihsize; @@ -460,10 +436,7 @@ l3_1tr6_disconn_req(struct PStack *st, byte pr, void *arg) i_down(st, dibh); - if (rejflg) - newl3state(st, 0); - else - newl3state(st, 11); + newl3state(st, 11); } static void @@ -473,8 +446,6 @@ l3_1tr6_rel_req(struct PStack *st, byte pr, void *arg) newl3state(st, 19); } - - static struct stateentry downstatelist_1tr6t[] = { {0, CC_SETUP_REQ, l3_1tr6_setup}, diff --git a/drivers/isdn/teles/l3_1TR6.h b/drivers/isdn/teles/l3_1TR6.h index 451d7af58662..a3502fb36dc4 100644 --- a/drivers/isdn/teles/l3_1TR6.h +++ b/drivers/isdn/teles/l3_1TR6.h @@ -1,6 +1,9 @@ -/* $Id: l3_1TR6.h,v 1.1 1996/04/13 10:25:42 fritz Exp $ +/* $Id: l3_1TR6.h,v 1.3 1996/04/30 21:53:48 isdn4dev Exp $ * * $Log: l3_1TR6.h,v $ + * Revision 1.3 1996/04/30 21:53:48 isdn4dev + * Bugs, SPV, Logging in q931.c Karsten Keil + * * Revision 1.1 1996/04/13 10:25:42 fritz * Initial revision * @@ -15,16 +18,16 @@ /* * MsgType N0 */ -#define MT_N0_REG_IND 61 -#define MT_N0_CANC_IND 62 -#define MT_N0_FAC_STA 63 -#define MT_N0_STA_ACK 64 -#define MT_N0_STA_REJ 65 -#define MT_N0_FAC_INF 66 -#define MT_N0_INF_ACK 67 -#define MT_N0_INF_REJ 68 -#define MT_N0_CLOSE 75 -#define MT_N0_CLO_ACK 77 +#define MT_N0_REG_IND 0x61 +#define MT_N0_CANC_IND 0x62 +#define MT_N0_FAC_STA 0x63 +#define MT_N0_STA_ACK 0x64 +#define MT_N0_STA_REJ 0x65 +#define MT_N0_FAC_INF 0x66 +#define MT_N0_INF_ACK 0x67 +#define MT_N0_INF_REJ 0x68 +#define MT_N0_CLOSE 0x75 +#define MT_N0_CLO_ACK 0x77 /* @@ -63,59 +66,6 @@ #define MT_N1_STAT 0x63 -struct MTypeDesc { - byte mt; - char *descr; -}; - -static struct MTypeDesc mtdesc_n0[] = -{ - {MT_N0_REG_IND, "MT_N0_REG_IND"}, - {MT_N0_CANC_IND, "MT_N0_CANC_IND"}, - {MT_N0_FAC_STA, "MT_N0_FAC_STA"}, - {MT_N0_STA_ACK, "MT_N0_STA_ACK"}, - {MT_N0_STA_REJ, "MT_N0_STA_REJ"}, - {MT_N0_FAC_INF, "MT_N0_FAC_INF"}, - {MT_N0_INF_ACK, "MT_N0_INF_ACK"}, - {MT_N0_INF_REJ, "MT_N0_INF_REJ"}, - {MT_N0_CLOSE, "MT_N0_CLOSE"}, - {MT_N0_CLO_ACK, "MT_N0_CLO_ACK"} -}; - -static struct MTypeDesc mtdesc_n1[] = -{ - {MT_N1_ESC, "MT_N1_ESC"}, - {MT_N1_ALERT, "MT_N1_ALERT"}, - {MT_N1_CALL_SENT, "MT_N1_CALL_SENT"}, - {MT_N1_CONN, "MT_N1_CONN"}, - {MT_N1_CONN_ACK, "MT_N1_CONN_ACK"}, - {MT_N1_SETUP, "MT_N1_SETUP"}, - {MT_N1_SETUP_ACK, "MT_N1_SETUP_ACK"}, - {MT_N1_RES, "MT_N1_RES"}, - {MT_N1_RES_ACK, "MT_N1_RES_ACK"}, - {MT_N1_RES_REJ, "MT_N1_RES_REJ"}, - {MT_N1_SUSP, "MT_N1_SUSP"}, - {MT_N1_SUSP_ACK, "MT_N1_SUSP_ACK"}, - {MT_N1_SUSP_REJ, "MT_N1_SUSP_REJ"}, - {MT_N1_USER_INFO, "MT_N1_USER_INFO"}, - {MT_N1_DET, "MT_N1_DET"}, - {MT_N1_DISC, "MT_N1_DISC"}, - {MT_N1_REL, "MT_N1_REL"}, - {MT_N1_REL_ACK, "MT_N1_REL_ACK"}, - {MT_N1_CANC_ACK, "MT_N1_CANC_ACK"}, - {MT_N1_CANC_REJ, "MT_N1_CANC_REJ"}, - {MT_N1_CON_CON, "MT_N1_CON_CON"}, - {MT_N1_FAC, "MT_N1_FAC"}, - {MT_N1_FAC_ACK, "MT_N1_FAC_ACK"}, - {MT_N1_FAC_CAN, "MT_N1_FAC_CAN"}, - {MT_N1_FAC_REG, "MT_N1_FAC_REG"}, - {MT_N1_FAC_REJ, "MT_N1_FAC_REJ"}, - {MT_N1_INFO, "MT_N1_INFO"}, - {MT_N1_REG_ACK, "MT_N1_REG_ACK"}, - {MT_N1_REG_REJ, "MT_N1_REG_REJ"}, - {MT_N1_STAT, "MT_N1_STAT"} -}; - /* * W Elemente @@ -172,7 +122,7 @@ static struct MTypeDesc mtdesc_n1[] = #define FAC_Unterdruecke 0x1B #define FAC_Deactivate 0x1E #define FAC_Activate 0x1D -#define FAC_SVC 0x1F +#define FAC_SPV 0x1F #define FAC_Rueckwechsel 0x23 #define FAC_Umleitung 0x24 @@ -187,7 +137,7 @@ static struct MTypeDesc mtdesc_n1[] = #define CAUSE_FacNotImpl 0x10 #define CAUSE_FacNotSubscr 0x11 #define CAUSE_OutgoingBarred 0x20 -#define CAUSE_UserAssessBusy 0x21 +#define CAUSE_UserAccessBusy 0x21 #define CAUSE_NegativeGBG 0x22 #define CAUSE_UnknownGBG 0x23 #define CAUSE_NoSPVknown 0x25 diff --git a/drivers/isdn/teles/llglue.c b/drivers/isdn/teles/llglue.c index 8c164333032d..4f331504a10a 100644 --- a/drivers/isdn/teles/llglue.c +++ b/drivers/isdn/teles/llglue.c @@ -1,6 +1,12 @@ -/* $Id: llglue.c,v 1.1 1996/04/13 10:26:29 fritz Exp $ +/* $Id: llglue.c,v 1.3 1996/05/01 14:19:57 fritz Exp $ * * $Log: llglue.c,v $ + * Revision 1.3 1996/05/01 14:19:57 fritz + * Added ISDN_FEADTURE_L2_TRANS + * + * Revision 1.2 1996/04/29 23:01:46 fritz + * Added driverId and channel to readstatus(). + * * Revision 1.1 1996/04/13 10:26:29 fritz * Initial revision * @@ -25,7 +31,7 @@ static byte *teles_status_write = NULL; static byte *teles_status_end = NULL; int -teles_readstatus(byte * buf, int len, int user) +teles_readstatus(byte * buf, int len, int user, int id, int channel) { int count; byte *p; @@ -90,6 +96,7 @@ ll_init(void) iif.features = ISDN_FEATURE_L2_X75I | ISDN_FEATURE_L2_HDLC | + ISDN_FEATURE_L2_TRANS | ISDN_FEATURE_L3_TRANS | ISDN_FEATURE_P_1TR6 | ISDN_FEATURE_P_EURO; diff --git a/drivers/isdn/teles/q931.c b/drivers/isdn/teles/q931.c index 4e740bd639c7..ab8b7947f026 100644 --- a/drivers/isdn/teles/q931.c +++ b/drivers/isdn/teles/q931.c @@ -1,4 +1,4 @@ -/* $Id: q931.c,v 1.2 1996/04/20 16:48:19 fritz Exp $ +/* $Id: q931.c,v 1.4 1996/05/17 03:46:17 fritz Exp $ * * q931.c code to decode ITU Q.931 call control messages * @@ -10,7 +10,16 @@ * * Beat Doebeli cause texts, display information element * + * Karsten Keil cause texts, display information element for 1TR6 + * + * * $Log: q931.c,v $ + * Revision 1.4 1996/05/17 03:46:17 fritz + * General cleanup. + * + * Revision 1.3 1996/04/30 22:06:50 isdn4dev + * logging 1TR6 messages correctly Karsten Keil + * * Revision 1.2 1996/04/20 16:48:19 fritz * Misc. typos * @@ -23,6 +32,7 @@ #define __NO_VERSION__ #include "teles.h" +#include "l3_1TR6.h" byte * findie(byte * p, int size, byte ie, int wanted_set) @@ -174,9 +184,87 @@ struct MessageType { #define MTSIZE sizeof(mtlist)/sizeof(struct MessageType) +static +struct MessageType mt_n0[] = +{ + {MT_N0_REG_IND, "REGister INDication"}, + {MT_N0_CANC_IND, "CANCel INDication"}, + {MT_N0_FAC_STA, "FACility STAtus"}, + {MT_N0_STA_ACK, "STAtus ACKnowledge"}, + {MT_N0_STA_REJ, "STAtus REJect"}, + {MT_N0_FAC_INF, "FACility INFormation"}, + {MT_N0_INF_ACK, "INFormation ACKnowledge"}, + {MT_N0_INF_REJ, "INFormation REJect"}, + {MT_N0_CLOSE, "CLOSE"}, + {MT_N0_CLO_ACK, "CLOse ACKnowledge"} +}; + +int mt_n0_len = (sizeof(mt_n0) / sizeof(struct MessageType)); static -int +struct MessageType mt_n1[] = +{ + {MT_N1_ESC, "ESCape"}, + {MT_N1_ALERT, "ALERT"}, + {MT_N1_CALL_SENT, "CALL SENT"}, + {MT_N1_CONN, "CONNect"}, + {MT_N1_CONN_ACK, "CONNect ACKnowledge"}, + {MT_N1_SETUP, "SETUP"}, + {MT_N1_SETUP_ACK, "SETUP ACKnowledge"}, + {MT_N1_RES, "RESume"}, + {MT_N1_RES_ACK, "RESume ACKnowledge"}, + {MT_N1_RES_REJ, "RESume REJect"}, + {MT_N1_SUSP, "SUSPend"}, + {MT_N1_SUSP_ACK, "SUSPend ACKnowledge"}, + {MT_N1_SUSP_REJ, "SUSPend REJect"}, + {MT_N1_USER_INFO, "USER INFO"}, + {MT_N1_DET, "DETach"}, + {MT_N1_DISC, "DISConnect"}, + {MT_N1_REL, "RELease"}, + {MT_N1_REL_ACK, "RELease ACKnowledge"}, + {MT_N1_CANC_ACK, "CANCel ACKnowledge"}, + {MT_N1_CANC_REJ, "CANCel REJect"}, + {MT_N1_CON_CON, "CONgestion CONtrol"}, + {MT_N1_FAC, "FACility"}, + {MT_N1_FAC_ACK, "FACility ACKnowledge"}, + {MT_N1_FAC_CAN, "FACility CANcel"}, + {MT_N1_FAC_REG, "FACility REGister"}, + {MT_N1_FAC_REJ, "FACility REJect"}, + {MT_N1_INFO, "INFOmation"}, + {MT_N1_REG_ACK, "REGister ACKnowledge"}, + {MT_N1_REG_REJ, "REGister REJect"}, + {MT_N1_STAT, "STATus"} +}; + +int mt_n1_len = (sizeof(mt_n1) / sizeof(struct MessageType)); + +static struct MessageType fac_1tr6[] = +{ + {FAC_Sperre, "Sperre"}, + {FAC_Forward1, "Forward 1"}, + {FAC_Forward2, "Forward 2"}, + {FAC_Konferenz, "Konferenz"}, + {FAC_GrabBchan, "Grab Bchannel"}, + {FAC_Reactivate, "Reactivate"}, + {FAC_Konferenz3, "Dreier Konferenz"}, + {FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"}, + {FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"}, + {FAC_NummernIdent, "Rufnummer-Identifizierung"}, + {FAC_GBG, "GBG"}, + {FAC_DisplayUebergeben, "Display Uebergeben"}, + {FAC_DisplayUmgeleitet, "Display Umgeleitet"}, + {FAC_Unterdruecke, "Unterdruecke Rufnummer"}, + {FAC_Deactivate, "Deactivate"}, + {FAC_Activate, "Activate"}, + {FAC_SPV, "SPV"}, + {FAC_Rueckwechsel, "Rueckwechsel"}, + {FAC_Umleitung, "Umleitung"} +}; +int fac_1tr6_len = (sizeof(fac_1tr6) / sizeof(struct MessageType)); + + + +static int prbits(char *dest, byte b, int start, int len) { char *dp = dest; @@ -449,12 +537,6 @@ prcause(char *dest, byte * p) else dp += sprintf(dp, " cause value %x : %s \n", cause, cvlist[i].edescr); - -#if 0 - dp += sprintf(dp," cause value "); - dp += prbits(dp,*p++,7,7); - *dp++ = '\n'; -#endif while (!0) { if (p > end) break; @@ -471,10 +553,76 @@ prcause(char *dest, byte * p) } static -int -prchident(char *dest, byte * p) +struct MessageType cause_1tr6[] = +{ + {CAUSE_InvCRef, "Invalid Call Reference"}, + {CAUSE_BearerNotImpl, "Bearer Service Not Implemented"}, + {CAUSE_CIDunknown, "Caller Identity unknown"}, + {CAUSE_CIDinUse, "Caller Identity in Use"}, + {CAUSE_NoChans, "No Channels available"}, + {CAUSE_FacNotImpl, "Facility Not Implemented"}, + {CAUSE_FacNotSubscr, "Facility Not Subscribed"}, + {CAUSE_OutgoingBarred, "Outgoing calls barred"}, + {CAUSE_UserAccessBusy, "User Access Busy"}, + {CAUSE_NegativeGBG, "Negative GBG"}, + {CAUSE_UnknownGBG, "Unknown GBG"}, + {CAUSE_NoSPVknown, "No SPV known"}, + {CAUSE_DestNotObtain, "Destination not obtainable"}, + {CAUSE_NumberChanged, "Number changed"}, + {CAUSE_OutOfOrder, "Out Of Order"}, + {CAUSE_NoUserResponse, "No User Response"}, + {CAUSE_UserBusy, "User Busy"}, + {CAUSE_IncomingBarred, "Incoming Barred"}, + {CAUSE_CallRejected, "Call Rejected"}, + {CAUSE_NetworkCongestion, "Network Congestion"}, + {CAUSE_RemoteUser, "Remote User initiated"}, + {CAUSE_LocalProcErr, "Local Procedure Error"}, + {CAUSE_RemoteProcErr, "Remote Procedure Error"}, + {CAUSE_RemoteUserSuspend, "Remote User Suspend"}, + {CAUSE_RemoteUserResumed, "Remote User Resumed"}, + {CAUSE_UserInfoDiscarded, "User Info Discarded"} +}; + +int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType)); + +static int +prcause_1tr6(char *dest, byte * p) { char *dp = dest; + int i, cause; + + p++; + if (0 == *p) { + dp += sprintf(dp, " OK (cause length=0)\n"); + return (dp - dest); + } else if (*p > 1) { + dp += sprintf(dp, " coding "); + dp += prbits(dp, p[2], 7, 2); + dp += sprintf(dp, " location "); + dp += prbits(dp, p[2], 4, 4); + *dp++ = '\n'; + } + p++; + cause = 0x7f & *p; + + /* locate cause value */ + for (i = 0; i < cause_1tr6_len; i++) + if (cause_1tr6[i].nr == cause) + break; + + /* display cause value if it exists */ + if (i == cause_1tr6_len) + dp += sprintf(dp, "Unknown cause type %x!\n", cause); + else + dp += sprintf(dp, " cause value %x : %s \n", cause, cause_1tr6[i].descr); + + return (dp - dest); + +} + +static int +prchident(char *dest, byte * p) { + char *dp = dest; p += 2; dp += sprintf(dp, " octet 3 "); @@ -482,10 +630,9 @@ prchident(char *dest, byte * p) *dp++ = '\n'; return (dp - dest); } -static -int -prcalled(char *dest, byte * p) -{ + +static int +prcalled(char *dest, byte * p) { int l; char *dp = dest; @@ -500,10 +647,8 @@ prcalled(char *dest, byte * p) *dp++ = '\n'; return (dp - dest); } -static -int -prcalling(char *dest, byte * p) -{ +static int +prcalling(char *dest, byte * p) { int l; char *dp = dest; @@ -518,7 +663,6 @@ prcalling(char *dest, byte * p) *dp++ = '\n'; l--; }; - p++; dp += sprintf(dp, " number digits "); @@ -575,10 +719,8 @@ prbearer(char *dest, byte * p) return (dp - dest); } -static -int -general(char *dest, byte * p) -{ +static int +general(char *dest, byte * p) { char *dp = dest; char ch = ' '; int l, octet = 3; @@ -597,17 +739,44 @@ general(char *dest, byte * p) ch = ' '; } else if (ch == ' ') ch = 'a'; - else ch++; } return (dp - dest); } -static -int -display(char *dest, byte * p) -{ +static int +prcharge(char *dest, byte * p) { + char *dp = dest; + int l; + + p++; + l = *p++ - 1; + dp += sprintf(dp, " GEA "); + dp += prbits(dp, *p++, 8, 8); + dp += sprintf(dp, " Anzahl: "); + /* Iterate over all octets in the * information element */ + while (l--) + *dp++ = *p++; + *dp++ = '\n'; + return (dp - dest); +} +static int +prtext(char *dest, byte * p) { + char *dp = dest; + int l; + + p++; + l = *p++; + dp += sprintf(dp, " "); + /* Iterate over all octets in the * information element */ + while (l--) + *dp++ = *p++; + *dp++ = '\n'; + return (dp - dest); +} +static int +display(char *dest, byte * p) { char *dp = dest; char ch = ' '; int l, octet = 3; @@ -772,107 +941,206 @@ struct InformationElement { }, }; + #define IESIZE sizeof(ielist)/sizeof(struct InformationElement) -#ifdef FRITZDEBUG -void -hexdump(byte * buf, int len, char *comment) +static struct InformationElement we_0[] = { - static char dbuf[1024]; - char *p = dbuf; + {WE0_cause, "Cause", prcause_1tr6}, + {WE0_connAddr, "Connecting Address", prcalled}, + {WE0_callID, "Call IDentity", general}, + {WE0_chanID, "Channel IDentity", general}, + {WE0_netSpecFac, "Network Specific Facility", general}, + {WE0_display, "Display", general}, + {WE0_keypad, "Keypad", general}, + {WE0_origAddr, "Origination Address", prcalled}, + {WE0_destAddr, "Destination Address", prcalled}, + {WE0_userInfo, "User Info", general} +}; - p += sprintf(p, "%s: ", comment); - while (len) { - p += sprintf(p, "%02x ", *p++); - len--; - } - p += sprintf(p, "\n"); +static int we_0_len = (sizeof(we_0) / sizeof(struct InformationElement)); - teles_putstatus(dbuf); -} -#endif +static struct InformationElement we_6[] = +{ + {WE6_serviceInd, "Service Indicator", general}, + {WE6_chargingInfo, "Charging Information", prcharge}, + {WE6_date, "Date", prtext}, + {WE6_facSelect, "Facility Select", general}, + {WE6_facStatus, "Facility Status", general}, + {WE6_statusCalled, "Status Called", general}, + {WE6_addTransAttr, "Additional Transmission Attributes", general} +}; +static int we_6_len = (sizeof(we_6) / sizeof(struct InformationElement)); void -dlogframe(struct IsdnCardState *sp, byte * buf, int size, char *comment) -{ +dlogframe(struct IsdnCardState *sp, byte * buf, int size, char *comment) { byte *bend = buf + size; char *dp; - int i; + int i, cs = 0, cs_old = 0, cs_fest = 0; /* display header */ dp = sp->dlogspace; dp += sprintf(dp, "%s\n", comment); { - byte *p = buf; - + byte *p = buf; dp += sprintf(dp, "hex: "); while (p < bend) - dp += sprintf(dp, "%02x ", *p++); + dp += sprintf(dp, "%02x ", *p++); dp += sprintf(dp, "\n"); teles_putstatus(sp->dlogspace); dp = sp->dlogspace; - } - /* locate message type */ - for (i = 0; i < MTSIZE; i++) - if (mtlist[i].nr == buf[3]) - break; + } + if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */ + /* locate message type */ + if (buf[0] == PROTO_DIS_N0) { /* N0 */ + for (i = 0; i < mt_n0_len; i++) + if (mt_n0[i].nr == buf[3]) + break; + /* display message type iff it exists */ + if (i == mt_n0_len) + dp += sprintf(dp, "Unknown message type N0 %x!\n", buf[3]); + else + dp += sprintf(dp, "call reference %d size %d message type %s\n", + buf[2], size, mt_n0[i].descr); + } else { /* N1 */ + for (i = 0; i < mt_n1_len; i++) + if (mt_n1[i].nr == buf[3]) + break; + /* display message type iff it exists */ + if (i == mt_n1_len) + dp += sprintf(dp, "Unknown message type N1 %x!\n", buf[3]); + else + dp += sprintf(dp, "call reference %d size %d message type %s\n", + buf[2], size, mt_n1[i].descr); + } - /* display message type iff it exists */ - if (i == MTSIZE) - dp += sprintf(dp, "Unknown message type %x!\n", buf[3]); - else - dp += sprintf(dp, "call reference %d size %d message type %s\n", - buf[2], size, mtlist[i].descr); - - /* display each information element */ - buf += 4; - while (buf < bend) { - /* Is it a single octet information element? */ - if (*buf & 0x80) { - switch ((*buf >> 4) & 7) { - case 1: - dp += sprintf(dp, " Shift %x\n", *buf & 0xf); - break; - case 3: - dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); - break; - case 5: - dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf); - break; - case 2: - if (*buf == 0xa0) { - dp += sprintf(dp, " More data\n"); - break; - } - if (*buf == 0xa1) { - dp += sprintf(dp, " Sending complete\n"); - } - break; + /* display each information element */ + buf += 4; + while (buf < bend) { + /* Is it a single octet information element? */ + if (*buf & 0x80) { + switch ((*buf >> 4) & 7) { + case 1: + dp += sprintf(dp, " Shift %x\n", *buf & 0xf); + cs_old = cs; + cs = *buf & 7; + cs_fest = *buf & 8; + break; + case 3: + dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); + break; + case 2: + if (*buf == 0xa0) { + dp += sprintf(dp, " More data\n"); + break; + } + if (*buf == 0xa1) { + dp += sprintf(dp, " Sending complete\n"); + } + break; /* fall through */ - default: - dp += sprintf(dp, " Reserved %x\n", *buf); - break; + default: + dp += sprintf(dp, " Reserved %x\n", *buf); + break; + } + buf++; + continue; + } + /* No, locate it in the table */ + if (cs == 0) { + for (i = 0; i < we_0_len; i++) + if (*buf == we_0[i].nr) + break; + + /* When found, give appropriate msg */ + if (i != we_0_len) { + dp += sprintf(dp, " %s\n", we_0[i].descr); + dp += we_0[i].f(dp, buf); + } else + dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]); + } else if (cs == 6) { + for (i = 0; i < we_6_len; i++) + if (*buf == we_6[i].nr) + break; + + /* When found, give appropriate msg */ + if (i != we_6_len) { + dp += sprintf(dp, " %s\n", we_6[i].descr); + dp += we_6[i].f(dp, buf); + } else + dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]); + } else + dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]); + /* Skip to next element */ + if (cs_fest == 8) { + cs = cs_old; + cs_old = 0; + cs_fest = 0; } - buf++; - continue; + buf += buf[1] + 2; } - /* No, locate it in the table */ - for (i = 0; i < IESIZE; i++) - if (*buf == ielist[i].nr) + } else { /* EURO */ + /* locate message type */ + for (i = 0; i < MTSIZE; i++) + if (mtlist[i].nr == buf[3]) break; - /* When not found, give appropriate msg */ - if (i != IESIZE) { - dp += sprintf(dp, " %s\n", ielist[i].descr); - dp += ielist[i].f(dp, buf); - } else - dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + /* display message type iff it exists */ + if (i == MTSIZE) + dp += sprintf(dp, "Unknown message type %x!\n", buf[3]); + else + dp += sprintf(dp, "call reference %d size %d message type %s\n", + buf[2], size, mtlist[i].descr); - /* Skip to next element */ - buf += buf[1] + 2; - } + /* display each information element */ + buf += 4; + while (buf < bend) { + /* Is it a single octet information element? */ + if (*buf & 0x80) { + switch ((*buf >> 4) & 7) { + case 1: + dp += sprintf(dp, " Shift %x\n", *buf & 0xf); + break; + case 3: + dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); + break; + case 5: + dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf); + break; + case 2: + if (*buf == 0xa0) { + dp += sprintf(dp, " More data\n"); + break; + } + if (*buf == 0xa1) { + dp += sprintf(dp, " Sending complete\n"); + } + break; + /* fall through */ + default: + dp += sprintf(dp, " Reserved %x\n", *buf); + break; + } + buf++; + continue; + } + /* No, locate it in the table */ + for (i = 0; i < IESIZE; i++) + if (*buf == ielist[i].nr) + break; + /* When not found, give appropriate msg */ + if (i != IESIZE) { + dp += sprintf(dp, " %s\n", ielist[i].descr); + dp += ielist[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + + /* Skip to next element */ + buf += buf[1] + 2; + } + } dp += sprintf(dp, "\n"); teles_putstatus(sp->dlogspace); } diff --git a/drivers/isdn/teles/teles.h b/drivers/isdn/teles/teles.h index f0007f58d8d6..15ce659761d7 100644 --- a/drivers/isdn/teles/teles.h +++ b/drivers/isdn/teles/teles.h @@ -1,6 +1,9 @@ -/* $Id: teles.h,v 1.1 1996/04/13 10:29:00 fritz Exp $ +/* $Id: teles.h,v 1.2 1996/04/30 21:52:04 isdn4dev Exp $ * * $Log: teles.h,v $ + * Revision 1.2 1996/04/30 21:52:04 isdn4dev + * SPV for 1TR6 - Karsten + * * Revision 1.1 1996/04/13 10:29:00 fritz * Initial revision * @@ -288,6 +291,7 @@ struct Param { int chargeinfo; /* Charge Info - only for 1tr6 in * the moment */ + int spv; /* SPV Flag */ }; struct PStack { diff --git a/drivers/net/8390.c b/drivers/net/8390.c index 87008f8df6ad..9864106bafb8 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -617,7 +617,7 @@ static void ei_rx_overrun(struct device *dev) /* * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total. * Early datasheets said to poll the reset bit, but now they say that - * it "is not a reliable indicator and subequently should be ignored." + * it "is not a reliable indicator and subsequently should be ignored." * We wait at least 10ms. */ wait_start_time = jiffies; diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 1135fbb2e963..0ff16b74c815 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -58,7 +58,6 @@ static int dummy_xmit(struct sk_buff *skb, struct device *dev); static struct enet_statistics *dummy_get_stats(struct device *dev); #endif -#ifdef MODULE static int dummy_open(struct device *dev) { MOD_INC_USE_COUNT; @@ -70,7 +69,6 @@ static int dummy_close(struct device *dev) MOD_DEC_USE_COUNT; return 0; } -#endif int dummy_init(struct device *dev) @@ -89,10 +87,9 @@ int dummy_init(struct device *dev) memset(dev->priv, 0, sizeof(struct enet_statistics)); dev->get_stats = dummy_get_stats; #endif -#ifdef MODULE + dev->open = &dummy_open; dev->stop = &dummy_close; -#endif /* Fill in the fields of the device structure with ethernet-generic values. */ ether_setup(dev); diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 74181b54f93c..4986d1fed9fe 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -17,6 +17,9 @@ * Larry McVoy : Tiny tweak to double performance * Alan Cox : Backed out LMV's tweak - the linux mm * can't take it... + * Michael Griffith: Don't bother computing the checksums + * on packets received on the loopback + * interface. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 10e574e167b4..cd91ea15834a 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -271,6 +271,7 @@ plip_init(struct device *dev) dev->get_stats = plip_get_stats; dev->set_config = plip_config; dev->do_ioctl = plip_ioctl; + dev->tx_queue_len = 10; dev->flags = IFF_POINTOPOINT|IFF_NOARP; /* Set the private structure */ diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index 865e8bb0e9c5..e918642cb8fa 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -400,6 +400,7 @@ ppp_init_dev (struct device *dev) dev->get_stats = ppp_dev_stats; dev->do_ioctl = ppp_dev_ioctl; dev->addr_len = 0; + dev->tx_queue_len = 10; dev->type = ARPHRD_PPP; for (indx = 0; indx < DEV_NUMBUFFS; indx++) diff --git a/drivers/net/sdla.c b/drivers/net/sdla.c index 89058ab5567d..ff94f90987b7 100644 --- a/drivers/net/sdla.c +++ b/drivers/net/sdla.c @@ -367,7 +367,7 @@ static void sdla_errors(struct device *dev, int cmd, int dlci, int ret, int len, state = "active"; else { - sprintf(line, "uknown status: %02X", pstatus->flags); + sprintf(line, "unknown status: %02X", pstatus->flags); state = line; } printk(KERN_INFO "%s: DLCI %i: %s.\n", dev->name, pstatus->dlci, state); diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c index 5b868315e8c5..3f19301adc70 100644 --- a/drivers/net/slhc.c +++ b/drivers/net/slhc.c @@ -79,10 +79,7 @@ #include #include #include - -#ifdef __alpha__ -# include -#endif +#include int last_retran; @@ -619,11 +616,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) cp += (ip->ihl - 5) * 4; } -#ifdef __alpha__ - stw_u(ip_fast_csum(icp, ip->ihl), &((struct iphdr *)icp)->check); -#else - ((struct iphdr *)icp)->check = ip_fast_csum(icp, ((struct iphdr*)icp)->ihl); -#endif + put_unaligned(ip_fast_csum(icp, ip->ihl), + &((struct iphdr *)icp)->check); memcpy(cp, thp, 20); cp += 20; diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in index b1cd0cefcc45..a8ef97990c4f 100644 --- a/drivers/scsi/Config.in +++ b/drivers/scsi/Config.in @@ -42,7 +42,12 @@ if [ "$CONFIG_PCI" = "y" ]; then fi dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI -dep_tristate 'QLOGIC SCSI support' CONFIG_SCSI_QLOGIC $CONFIG_SCSI +dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI +if [ "$CONFIG_PCI" = "y" ]; then + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate 'Qlogic ISP SCSI support (EXPERIMENTAL)' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI + fi +fi dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index bfdbb86e9b8c..626a2ea37f8f 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -124,14 +124,24 @@ else endif endif -ifeq ($(CONFIG_SCSI_QLOGIC),y) -L_OBJS += qlogic.o +ifeq ($(CONFIG_SCSI_QLOGIC_FAS),y) +L_OBJS += qlogicfas.o else - ifeq ($(CONFIG_SCSI_QLOGIC),m) - M_OBJS += qlogic.o + ifeq ($(CONFIG_SCSI_QLOGIC_FAS),m) + M_OBJS += qlogicfas.o endif endif + +ifeq ($(CONFIG_SCSI_QLOGIC_ISP),y) +L_OBJS += qlogicisp.o +else + ifeq ($(CONFIG_SCSI_QLOGIC_ISP),m) + M_OBJS += qlogicisp.o + endif +endif + + ifeq ($(CONFIG_SCSI_AHA152X),y) L_OBJS += aha152x.o else diff --git a/drivers/scsi/README.qlogic b/drivers/scsi/README.qlogicfas similarity index 82% rename from drivers/scsi/README.qlogic rename to drivers/scsi/README.qlogicfas index 2c2d8409cc17..737a03fe7599 100644 --- a/drivers/scsi/README.qlogic +++ b/drivers/scsi/README.qlogicfas @@ -1,11 +1,19 @@ -RANDOM NOTES ON THE QLOGIC SCSI DRIVER +RANDOM NOTES ON THE QLOGICFAS SCSI DRIVER -This driver does NOT support the PCI version. It is a different chip. +This driver supports the Qlogic FASXXX family of chips. This driver +only works with the ISA, VLB, and PCMCIA versions of the Qlogic +FastSCSI! cards as well as any other card based on the FASXX chip +(including the Control Concepts SCSI/IDE/SIO/PIO/FDC cards). -It DOES support the ISA, VLB, and PCMCIA versions of the Qlogic FastSCSI! -cards as well as any other card based on the chip (including the Control -Concepts SCSI/IDE/SIO/PIO/FDC cards). +This driver does NOT support the PCI version. Support for these PCI +Qlogic boards: + + IQ-PCI + IQ-PCI-10 + IQ-PCI-D + +is provided by the qlogicisp.c driver. Check README.qlogicisp for details. PCMCIA SUPPORT @@ -62,4 +70,4 @@ detected). This can be caused by bad termination (the ACK can be reflected), or by noise when the chips work less well because of the heat, or when cables get too long for the speed. -If it doesn't work under DOS, it won't work under Linux. +Remember, if it doesn't work under DOS, it probably won't work under Linux. diff --git a/drivers/scsi/README.qlogicisp b/drivers/scsi/README.qlogicisp new file mode 100644 index 000000000000..ff2242c53c9a --- /dev/null +++ b/drivers/scsi/README.qlogicisp @@ -0,0 +1,26 @@ +Notes for the QLogic ISP1020 PCI SCSI Driver revision 0.6. + +This software should be considered ***BETA***. + +Be sure to include PCI BIOS support when rebuilding the kernel. + +The QLogic Corporation produces several PCI SCSI adapters: + + PCI-basic + IQ-PCI + IQ-PCI-10 + IQ-PCI-D + +This driver should work for all these adpaters, except for the PCI-basic which +does not use the ISP1020 chip. If you have the QLogic PCI-basic there is a +an am53c974 driver that supports your adapter. + +Much thanks to QLogic's tech support for providing the latest ISP1020 firmware, +and for taking the time to review my code. + +Erik Moe +ehm@cris.com + +Revised: +Michael A. Griffith +grif@cs.ucr.edu diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c index e16abe4a9e55..80e55aa6dcea 100644 --- a/drivers/scsi/atari_NCR5380.c +++ b/drivers/scsi/atari_NCR5380.c @@ -631,7 +631,7 @@ static void NCR5380_print_phase(struct Scsi_Host *instance) #else /* !NDEBUG */ -/* dummys... */ +/* dummies... */ __inline__ void NCR5380_print(struct Scsi_Host *instance) { }; __inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { }; diff --git a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h index b61b627c8e5b..8488ea39ad1c 100644 --- a/drivers/scsi/atari_scsi.h +++ b/drivers/scsi/atari_scsi.h @@ -107,7 +107,7 @@ int atari_scsi_release (struct Scsi_Host *); * MAIN -> NCR5380_main() control flow * NDAT -> no data-out phase * NWR -> no write commands - * PIO -> PIO tansfers + * PIO -> PIO transfers * PDMA -> pseudo DMA (unused on Atari) * QU -> queues * RSL -> reselections diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index 07f071b21d53..6250fefdd2eb 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -365,13 +365,29 @@ static struct error_info additional[] = #if (CONSTANTS & CONST_SENSE) static const char *snstext[] = { - "None","Recovered Error","Not Ready","Medium Error","Hardware Error", - "Illegal Request","Unit Attention","Data Protect","Blank Check", - "Key=9","Copy Aborted","Aborted Command","End-Of-Medium", - "Volume Overflow", "Miscompare", "Key=15"}; + "None", /* There is no sense information */ + "Recovered Error", /* The last command completed successfully + but used error correction */ + "Not Ready", /* The addressed target is not ready */ + "Medium Error", /* Data error detected on the medium */ + "Hardware Error", /* Controller or device failure */ + "Illegal Request", + "Unit Attention", /* Removable medium was changed, or + the target has been reset */ + "Data Protect", /* Access to the data is blocked */ + "Blank Check", /* Reached unexpected written or unwritten + region of the medium */ + "Key=9", /* Vendor specific */ + "Copy Aborted", /* COPY or COMPARE was aborted */ + "Aborted Command", /* The target aborted the command */ + "Equal", /* A SEARCH DATA command found data equal */ + "Volume Overflow", /* Medium full with still data to be written */ + "Miscompare", /* Source data and data on the medium + do not agree */ + "Key=15" /* Reserved */ +}; #endif - /* Print sense information */ void print_sense(const char * devclass, Scsi_Cmnd * SCpnt) { @@ -384,23 +400,29 @@ void print_sense(const char * devclass, Scsi_Cmnd * SCpnt) code = sense_buffer[0] & 0xf; valid = sense_buffer[0] & 0x80; - if (sense_class == 7) { + if (sense_class == 7) { /* extended sense data */ s = sense_buffer[7] + 8; - if(s > sizeof(SCpnt->sense_buffer)) s = sizeof(SCpnt->sense_buffer); + if(s > sizeof(SCpnt->sense_buffer)) + s = sizeof(SCpnt->sense_buffer); if (!valid) printk("extra data not valid "); - if (sense_buffer[2] & 0x80) printk( "FMK "); - if (sense_buffer[2] & 0x40) printk( "EOM "); - if (sense_buffer[2] & 0x20) printk( "ILI "); + if (sense_buffer[2] & 0x80) + printk( "FMK "); /* current command has read a filemark */ + if (sense_buffer[2] & 0x40) + printk( "EOM "); /* end-of-medium condition exists */ + if (sense_buffer[2] & 0x20) + printk( "ILI "); /* incorrect block length requested */ switch (code) { case 0x0: - error = "Current"; + error = "Current"; /* error concerns current command */ break; case 0x1: - error = "Deferred"; + error = "Deferred"; /* error concerns some earlier command */ + /* e.g., an earlier write to disk cache succeeded, but + now the disk discovers that it cannot write the data */ break; default: error = "Invalid"; @@ -437,7 +459,15 @@ void print_sense(const char * devclass, Scsi_Cmnd * SCpnt) #else printk("ASC=%2x ASCQ=%2x\n", sense_buffer[12], sense_buffer[13]); #endif - } else { + } else { /* non-extended sense data */ + + /* + * Standard says: + * sense_buffer[0] & 0200 : address valid + * sense_buffer[0] & 0177 : vendor-specific error code + * sense_buffer[1] & 0340 : vendor-specific + * sense_buffer[1..3] : 21-bit logical block address + */ #if (CONSTANTS & CONST_SENSE) if (sense_buffer[0] < 15) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index f35029d94ef9..6bf0a13f2289 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -109,8 +109,12 @@ #include "pas16.h" #endif -#ifdef CONFIG_SCSI_QLOGIC -#include "qlogic.h" +#ifdef CONFIG_SCSI_QLOGIC_FAS +#include "qlogicfas.h" +#endif + +#ifdef CONFIG_SCSI_QLOGIC_ISP +#include "qlogicisp.h" #endif #ifdef CONFIG_SCSI_SEAGATE @@ -250,8 +254,11 @@ static Scsi_Host_Template builtin_scsi_hosts[] = #ifdef CONFIG_SCSI_NCR53C406A /* 53C406A should come before QLOGIC */ NCR53c406a, #endif -#ifdef CONFIG_SCSI_QLOGIC - QLOGIC, +#ifdef CONFIG_SCSI_QLOGIC_FAS + QLOGICFAS, +#endif +#ifdef CONFIG_SCSI_QLOGIC_ISP + QLOGICISP, #endif #ifdef CONFIG_SCSI_PAS16 MV_PAS16, diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h index 471f32d2cee2..7de6dbd7b06b 100644 --- a/drivers/scsi/hosts.h +++ b/drivers/scsi/hosts.h @@ -235,7 +235,7 @@ typedef struct SHT * Scsi_Host_Template, except that we have one entry for each * actual physical host adapter on the system, stored as a linked * list. Note that if there are 2 aha1542 boards, then there will - * be two Scsi_Host entries, but only 1 Scsi_Host_Template entries. + * be two Scsi_Host entries, but only 1 Scsi_Host_Template entry. */ struct Scsi_Host diff --git a/drivers/scsi/qlogic.h b/drivers/scsi/qlogic.h deleted file mode 100644 index 0ff119ae72c4..000000000000 --- a/drivers/scsi/qlogic.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef _QLOGIC_H -#define _QLOGIC_H - -int qlogic_detect(Scsi_Host_Template * ); -const char * qlogic_info(struct Scsi_Host *); -int qlogic_command(Scsi_Cmnd *); -int qlogic_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); -int qlogic_abort(Scsi_Cmnd *); -int qlogic_reset(Scsi_Cmnd *); -int qlogic_biosparam(Disk *, kdev_t, int[]); - -#ifndef NULL -#define NULL (0) -#endif - -#define QLOGIC { \ - NULL, \ - NULL, \ - NULL, \ - NULL, \ - NULL, \ - qlogic_detect, \ - NULL, \ - qlogic_info, \ - qlogic_command, \ - qlogic_queuecommand, \ - qlogic_abort, \ - qlogic_reset, \ - NULL, \ - qlogic_biosparam, \ - 0, \ - -1, \ - SG_ALL, \ - 1, \ - 0, \ - 0, \ - DISABLE_CLUSTERING \ -} - -#endif /* _QLOGIC_H */ diff --git a/drivers/scsi/qlogic.c b/drivers/scsi/qlogicfas.c similarity index 95% rename from drivers/scsi/qlogic.c rename to drivers/scsi/qlogicfas.c index e4f15f9ccdc4..342d52a31563 100644 --- a/drivers/scsi/qlogic.c +++ b/drivers/scsi/qlogicfas.c @@ -18,7 +18,7 @@ Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994 (you can reference it, but it is incomplete and inaccurate in places) - Version 0.43 4/6/95 - kernel 1.2.0+, pcmcia 2.5.4+ + Version 0.44 5/7/96 - kernel 1.2.0+, pcmcia 2.5.4+ Functions as standalone, loadable, and PCMCIA driver, the latter from Dave Hind's PCMCIA package. @@ -127,11 +127,11 @@ #include #include "sd.h" #include "hosts.h" -#include "qlogic.h" +#include "qlogicfas.h" #include -struct proc_dir_entry proc_scsi_qlogic = { - PROC_SCSI_QLOGIC, 6, "qlogic", +struct proc_dir_entry proc_scsi_qlogicfas = { + PROC_SCSI_QLOGICFAS, 6, "qlogicfas", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; @@ -475,12 +475,12 @@ static void qlidone(Scsi_Cmnd * cmd) {}; /* null function */ #endif /* command process */ -int qlogic_command(Scsi_Cmnd * cmd) +int qlogicfas_command(Scsi_Cmnd * cmd) { int k; #if QL_USE_IRQ if (qlirq >= 0) { - qlogic_queuecommand(cmd, qlidone); + qlogicfas_queuecommand(cmd, qlidone); while (qlcmd != NULL); return cmd->result; } @@ -498,7 +498,7 @@ int k; #if QL_USE_IRQ /*----------------------------------------------------------------*/ /* queued command */ -int qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) +int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) { if(cmd->target == qinitid) { cmd->result = DID_BAD_TARGET << 16; @@ -514,7 +514,7 @@ int qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) return 0; } #else -int qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) +int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) { return 1; } @@ -524,7 +524,7 @@ int qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) /*----------------------------------------------------------------*/ /* allow PCMCIA code to preset the port */ /* port should be 0 and irq to -1 respectively for autoprobing */ -void qlogic_preset(int port, int irq) +void qlogicfas_preset(int port, int irq) { qbase=port; qlirq=irq; @@ -533,14 +533,14 @@ void qlogic_preset(int port, int irq) /*----------------------------------------------------------------*/ /* look for qlogic card and init if found */ -int qlogic_detect(Scsi_Host_Template * host) +int qlogicfas_detect(Scsi_Host_Template * host) { int i, j; /* these are only used by IRQ detect */ int qltyp; /* type of chip */ struct Scsi_Host *hreg; /* registered host structure */ unsigned long flags; -host->proc_dir = &proc_scsi_qlogic; +host->proc_dir = &proc_scsi_qlogicfas; /* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself decodes the address - I check 230 first since MIDI cards are typically at 330 @@ -609,7 +609,7 @@ host->proc_dir = &proc_scsi_qlogic; else printk( "Ql: Using preset IRQ %d\n", qlirq ); - if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogic", NULL)) + if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogicfas", NULL)) host->can_queue = 1; #endif request_region( qbase , 0x10 ,"qlogic"); @@ -620,7 +620,7 @@ host->proc_dir = &proc_scsi_qlogic; if( qlirq != -1 ) hreg->irq = qlirq; - sprintf(qinfo, "Qlogic Driver version 0.43, chip %02X at %03X, IRQ %d, TPdma:%d", + sprintf(qinfo, "Qlogicfas Driver version 0.44, chip %02X at %03X, IRQ %d, TPdma:%d", qltyp, qbase, qlirq, QL_TURBO_PDMA ); host->name = qinfo; @@ -629,7 +629,7 @@ host->proc_dir = &proc_scsi_qlogic; /*----------------------------------------------------------------*/ /* return bios parameters */ -int qlogic_biosparam(Disk * disk, kdev_t dev, int ip[]) +int qlogicfas_biosparam(Disk * disk, kdev_t dev, int ip[]) { /* This should mimic the DOS Qlogic driver's behavior exactly */ ip[0] = 0x40; @@ -647,7 +647,7 @@ int qlogic_biosparam(Disk * disk, kdev_t dev, int ip[]) /*----------------------------------------------------------------*/ /* abort command in progress */ -int qlogic_abort(Scsi_Cmnd * cmd) +int qlogicfas_abort(Scsi_Cmnd * cmd) { qabort = 1; ql_zap(); @@ -656,7 +656,7 @@ int qlogic_abort(Scsi_Cmnd * cmd) /*----------------------------------------------------------------*/ /* reset SCSI bus */ -int qlogic_reset(Scsi_Cmnd * cmd) +int qlogicfas_reset(Scsi_Cmnd * cmd) { qabort = 2; ql_zap(); @@ -665,14 +665,15 @@ int qlogic_reset(Scsi_Cmnd * cmd) /*----------------------------------------------------------------*/ /* return info string */ -const char *qlogic_info(struct Scsi_Host * host) +const char *qlogicfas_info(struct Scsi_Host * host) { return qinfo; } #ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = QLOGIC; +Scsi_Host_Template driver_template = QLOGICFAS; #include "scsi_module.c" #endif + diff --git a/drivers/scsi/qlogicfas.h b/drivers/scsi/qlogicfas.h new file mode 100644 index 000000000000..4e0457f9bff7 --- /dev/null +++ b/drivers/scsi/qlogicfas.h @@ -0,0 +1,43 @@ +#ifndef _QLOGICFAS_H +#define _QLOGICFAS_H + +int qlogicfas_detect(Scsi_Host_Template * ); +const char * qlogicfas_info(struct Scsi_Host *); +int qlogicfas_command(Scsi_Cmnd *); +int qlogicfas_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +int qlogicfas_abort(Scsi_Cmnd *); +int qlogicfas_reset(Scsi_Cmnd *); +int qlogicfas_biosparam(Disk *, kdev_t, int[]); + +#ifndef NULL +#define NULL (0) +#endif + +#define QLOGICFAS { \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + qlogicfas_detect, \ + NULL, \ + qlogicfas_info, \ + qlogicfas_command, \ + qlogicfas_queuecommand, \ + qlogicfas_abort, \ + qlogicfas_reset, \ + NULL, \ + qlogicfas_biosparam, \ + 0, \ + -1, \ + SG_ALL, \ + 1, \ + 0, \ + 0, \ + DISABLE_CLUSTERING \ +} + +#endif /* _QLOGICFAS_H */ + + + diff --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c new file mode 100644 index 000000000000..a400909dfad2 --- /dev/null +++ b/drivers/scsi/qlogicisp.c @@ -0,0 +1,1599 @@ +/* + * QLogic ISP1020 Intelligent SCSI Processor Driver (PCI) + * Written by Erik H. Moe, ehm@cris.com + * Copyright 1995, Erik H. Moe + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +/* Renamed and updated to 1.3.x by Michael Griffith */ + +/* + * $Date: 1995/09/22 02:23:15 $ + * $Revision: 0.5 $ + * + * $Log: isp1020.c,v $ + * Revision 0.5 1995/09/22 02:23:15 root + * do auto request sense + * + * Revision 0.4 1995/08/07 04:44:33 root + * supply firmware with driver. + * numerous bug fixes/general cleanup of code. + * + * Revision 0.3 1995/07/16 16:15:39 root + * added reset/abort code. + * + * Revision 0.2 1995/06/29 03:14:19 root + * fixed biosparam. + * added queue protocol. + * + * Revision 0.1 1995/06/25 01:55:45 root + * Initial release. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd.h" +#include "hosts.h" +#include "qlogicisp.h" + +/* Configuration section *****************************************************/ + +/* Set the following macro to 1 to reload the ISP1020's firmware. This is + the latest firmware provided by QLogic. This may be an earlier/later + revision than supplied by your board. */ + +#define RELOAD_FIRMWARE 1 + +/* Set the following macro to 1 to reload the ISP1020's defaults from nvram. + If you are not sure of your settings, leave this alone, the driver will + use a set of 'safe' defaults */ + +#define USE_NVRAM_DEFAULTS 0 + +/* Set this macro to 1 if you want to create a scsi loadable module. */ + +#define MODULE 0 + +/* Macros used for debuging */ + +#define DEBUG_ISP1020 0 +#define DEBUG_ISP1020_INT 0 +#define DEBUG_ISP1020_SETUP 0 + +/* End Configuration section *************************************************/ + +#include + +#if DEBUG_ISP1020 +#define ENTER(x) printk("isp1020 : entering %s()\n", x); +#define LEAVE(x) printk("isp1020 : leaving %s()\n", x); +#define DEBUG(x) x +#else +#define ENTER(x) +#define LEAVE(x) +#define DEBUG(x) +#endif /* DEBUG_ISP1020 */ + +#if DEBUG_ISP1020_INTR +#define ENTER_INTR(x) printk("isp1020 : entering %s()\n", x); +#define LEAVE_INTR(x) printk("isp1020 : leaving %s()\n", x); +#define DEBUG_INTR(x) x +#else +#define ENTER_INTR(x) +#define LEAVE_INTR(x) +#define DEBUG_INTR(x) +#endif /* DEBUG ISP1020_INTR */ + +#define ISP1020_REV_ID 1 + +/* host configuration and control registers */ +#define HOST_HCCR 0xc0 /* host command and control */ + +/* pci bus interface registers */ +#define PCI_ID_LOW 0x00 /* vendor id */ +#define PCI_ID_HIGH 0x02 /* device id */ +#define ISP_CFG0 0x04 /* configuration register #0 */ +#define ISP_CFG1 0x08 /* configuration register #1 */ +#define PCI_INTF_CTL 0x08 /* pci interface control */ +#define PCI_INTF_STS 0x0a /* pci interface status */ +#define PCI_SEMAPHORE 0x0c /* pci semaphore */ +#define PCI_NVRAM 0x0e /* pci nvram interface */ + +/* mailbox registers */ +#define MBOX0 0x70 /* mailbox 0 */ +#define MBOX1 0x72 /* mailbox 1 */ +#define MBOX2 0x74 /* mailbox 2 */ +#define MBOX3 0x76 /* mailbox 3 */ +#define MBOX4 0x78 /* mailbox 4 */ +#define MBOX5 0x7a /* mailbox 5 */ + +/* mailbox command complete status codes */ +#define MBOX_COMMAND_COMPLETE 0x4000 +#define INVALID_COMMAND 0x4001 +#define HOST_INTERFACE_ERROR 0x4002 +#define TEST_FAILED 0x4003 +#define COMMAND_ERROR 0x4005 +#define COMMAND_PARAM_ERROR 0x4006 + +/* async event status codes */ +#define ASYNC_SCSI_BUS_RESET 0x8001 +#define SYSTEM_ERROR 0x8002 +#define REQUEST_TRANSFER ERROR 0x8003 +#define RESPONSE_TRANSFER_ERROR 0x8004 +#define REQUEST_QUEUE_WAKEUP 0x8005 +#define EXECUTION_TIMEOUT_RESET 0x8006 + +struct Entry_header { + u_char entry_type; + u_char entry_cnt; + u_char sys_def_1; + u_char flags; +}; + +/* entry header type commands */ +#define ENTRY_COMMAND 1 +#define ENTRY_CONTINUATION 2 +#define ENTRY_STATUS 3 +#define ENTRY_MARKER 4 +#define ENTRY_EXTENDED_COMMAND 5 + +/* entry header flag definitions */ +#define EFLAG_CONTINUATION 1 +#define EFLAG_BUSY 2 +#define EFLAG_BAD_HEADER 4 +#define EFLAG_BAD_PAYLOAD 8 + +struct dataseg { + caddr_t d_base; + u_long d_count; +}; + +struct Command_Entry { + struct Entry_header hdr; + caddr_t handle; + u_char target_lun; + u_char target_id; + u_short cdb_length; + u_short control_flags; + u_short rsvd; + u_short time_out; + u_short segment_cnt; + u_char cdb[12]; + struct dataseg dataseg0; + struct dataseg dataseg1; + struct dataseg dataseg2; + struct dataseg dataseg3; +}; + +/* command entry control flag definitions */ +#define CFLAG_NODISC 0x01 +#define CFLAG_HEAD_TAG 0x02 +#define CFLAG_ORDERED_TAG 0x04 +#define CFLAG_SIMPLE_TAG 0x08 +#define CFLAG_TAR_RTN 0x10 +#define CFLAG_READ 0x20 +#define CFLAG_WRITE 0x40 + +struct Ext_Command_Entry { + struct Entry_header hdr; + caddr_t handle; + u_char target_lun; + u_char target_id; + u_short cdb_length; + u_short control_flags; + u_short rsvd; + u_short time_out; + u_short segment_cnt; + u_char cdb[44]; +}; + +struct Continuation_Entry { + struct Entry_header hdr; + u_long reserved; + struct dataseg dataseg0; + struct dataseg dataseg1; + struct dataseg dataseg2; + struct dataseg dataseg3; + struct dataseg dataseg4; + struct dataseg dataseg5; + struct dataseg dataseg6; +}; + +struct Marker_Entry { + struct Entry_header hdr; + caddr_t reserved; + u_char target_lun; + u_char target_id; + u_char modifier; + u_char rsvd; + u_char rsvds[52]; +}; + +/* marker entry modifier definitions */ +#define SYNC_DEVICE 0 +#define SYNC_TARGET 1 +#define SYNC_ALL 2 + +struct Status_Entry { + struct Entry_header hdr; + caddr_t handle; + u_short scsi_status; + u_short completion_status; + u_short state_flags; + u_short status_flags; + u_short time; + u_short req_sense_len; + u_long residual; + u_char rsvd[8]; + u_char req_sense_data[32]; +}; + +/* status entry completion status definitions */ +#define CS_COMPLETE 0x0000 +#define CS_INCOMPLETE 0x0001 +#define CS_DMA_ERROR 0x0002 +#define CS_TRANSPORT_ERROR 0x0003 +#define CS_RESET_OCCURRED 0x0004 +#define CS_ABORTED 0x0005 +#define CS_TIMEOUT 0x0006 +#define CS_DATA_OVERRUN 0x0007 +#define CS_COMMAND_OVERRUN 0x0008 +#define CS_STATUS_OVERRUN 0x0009 +#define CS_BAD_MESSAGE 0x000a +#define CS_NO_MESSAGE_OUT 0x000b +#define CS_EXT_ID_FAILED 0x000c +#define CS_IDE_MSG_FAILED 0x000d +#define CS_ABORT_MSG_FAILED 0x000e +#define CS_REJECT_MSG_FAILED 0x000f +#define CS_NOP_MSG_FAILED 0x0010 +#define CS_PARITY_ERROR_MSG_FAILED 0x0011 +#define CS_DEVICE_RESET_MSG_FAILED 0x0012 +#define CS_ID_MSG_FAILED 0x0013 +#define CS_UNEXP_BUS_FREE 0x0014 +#define CS_DATA_UNDERRUN 0x0015 + +/* status entry state flag definitions */ +#define SF_GOT_BUS 0x0100 +#define SF_GOT_TARGET 0x0200 +#define SF_SENT_CDB 0x0400 +#define SF_TRANSFERRED_DATA 0x0800 +#define SF_GOT_STATUS 0x1000 +#define SF_GOT_SENSE 0x2000 + +/* status entry status flag definitions */ +#define STF_DISCONNECT 0x0001 +#define STF_SYNCHRONOUS 0x0002 +#define STF_PARITY_ERROR 0x0004 +#define STF_BUS_RESET 0x0008 +#define STF_DEVICE_RESET 0x0010 +#define STF_ABORTED 0x0020 +#define STF_TIMEOUT 0x0040 +#define STF_NEGOTIATION 0x0080 + +/* host control commands */ +#define HCCR_NOP 0x0000 +#define HCCR_RESET 0x1000 +#define HCCR_PAUSE 0x2000 +#define HCCR_RELEASE 0x3000 +#define HCCR_SINGLE_STEP 0x4000 +#define HCCR_SET_HOST_INTR 0x5000 +#define HCCR_CLEAR_HOST_INTR 0x6000 +#define HCCR_CLEAR_RISC_INTR 0x7000 +#define HCCR_BP_ENABLE 0x8000 +#define HCCR_BIOS_ENABLE 0x9000 +#define HCCR_TEST_MODE 0xf000 + +/* mailbox commands */ +#define MBOX_NO_OP 0x0000 +#define MBOX_LOAD_RAM 0x0001 +#define MBOX_EXEC_FIRMWARE 0x0002 +#define MBOX_DUMP_RAM 0x0003 +#define MBOX_WRITE_RAM_WORD 0x0004 +#define MBOX_READ_RAM_WORD 0x0005 +#define MBOX_MAILBOX_REG_TEST 0x0006 +#define MBOX_VERIFY_CHECKSUM 0x0007 +#define MBOX_ABOUT_FIRMWARE 0x0008 +#define MBOX_CHECK_FIRMWARE 0x000e +#define MBOX_INIT_REQ_QUEUE 0x0010 +#define MBOX_INIT_RES_QUEUE 0x0011 +#define MBOX_EXECUTE_IOCB 0x0012 +#define MBOX_WAKE_UP 0x0013 +#define MBOX_STOP_FIRMWARE 0x0014 +#define MBOX_ABORT 0x0015 +#define MBOX_ABORT_DEVICE 0x0016 +#define MBOX_ABORT_TARGET 0x0017 +#define MBOX_BUS_RESET 0x0018 +#define MBOX_STOP_QUEUE 0x0019 +#define MBOX_START_QUEUE 0x001a +#define MBOX_SINGLE_STEP_QUEUE 0x001b +#define MBOX_ABORT_QUEUE 0x001c +#define MBOX_GET_DEV_QUEUE_STATUS 0x001d +#define MBOX_GET_FIRMWARE_STATUS 0x001f +#define MBOX_GET_INIT_SCSI_ID 0x0020 +#define MBOX_GET_SELECT_TIMEOUT 0x0021 +#define MBOX_GET_RETRY_COUNT 0x0022 +#define MBOX_GET_TAG_AGE_LIMIT 0x0023 +#define MBOX_GET_CLOCK_RATE 0x0024 +#define MBOX_GET_ACT_NEG_STATE 0x0025 +#define MBOX_GET_ASYNC_DATA_SETUP_TIME 0x0026 +#define MBOX_GET_PCI_PARAMS 0x0027 +#define MBOX_GET_TARGET_PARAMS 0x0028 +#define MBOX_GET_DEV_QUEUE_PARAMS 0x0029 +#define MBOX_SET_INIT_SCSI_ID 0x0030 +#define MBOX_SET_SELECT_TIMEOUT 0x0031 +#define MBOX_SET_RETRY_COUNT 0x0032 +#define MBOX_SET_TAG_AGE_LIMIT 0x0033 +#define MBOX_SET_CLOCK_RATE 0x0034 +#define MBOX_SET_ACTIVE_NEG_STATE 0x0035 +#define MBOX_SET_ASYNC_DATA_SETUP_TIME 0x0036 +#define MBOX_SET_PCI_CONTROL_PARAMS 0x0037 +#define MBOX_SET_TARGET_PARAMS 0x0038 +#define MBOX_SET_DEV_QUEUE_PARAMS 0x0039 +#define MBOX_RETURN_BIOS_BLOCK_ADDR 0x0040 +#define MBOX_WRITE_FOUR_RAM_WORDS 0x0041 +#define MBOX_EXEC_BIOS_IOCB 0x0042 + +#include "qlogicisp_asm.c" + +#define PACKB(a, b) (((a)<<4)|(b)) + +u_char mbox_param[] = { + PACKB(1, 1), /* MBOX_NO_OP */ + PACKB(5, 5), /* MBOX_LOAD_RAM */ + PACKB(2, 0), /* MBOX_EXEC_FIRMWARE */ + PACKB(5, 5), /* MBOX_DUMP_RAM */ + PACKB(3, 3), /* MBOX_WRITE_RAM_WORD */ + PACKB(2, 3), /* MBOX_READ_RAM_WORD */ + PACKB(6, 6), /* MBOX_MAILBOX_REG_TEST */ + PACKB(2, 3), /* MBOX_VERIFY_CHECKSUM */ + PACKB(1, 3), /* MBOX_ABOUT_FIRMWARE */ + PACKB(0, 0), /* 0x0009 */ + PACKB(0, 0), /* 0x000a */ + PACKB(0, 0), /* 0x000b */ + PACKB(0, 0), /* 0x000c */ + PACKB(0, 0), /* 0x000d */ + PACKB(1, 2), /* MBOX_CHECK_FIRMWARE */ + PACKB(0, 0), /* 0x000f */ + PACKB(5, 5), /* MBOX_INIT_REQ_QUEUE */ + PACKB(6, 6), /* MBOX_INIT_RES_QUEUE */ + PACKB(4, 4), /* MBOX_EXECUTE_IOCB */ + PACKB(2, 2), /* MBOX_WAKE_UP */ + PACKB(1, 6), /* MBOX_STOP_FIRMWARE */ + PACKB(4, 4), /* MBOX_ABORT */ + PACKB(2, 2), /* MBOX_ABORT_DEVICE */ + PACKB(3, 3), /* MBOX_ABORT_TARGET */ + PACKB(2, 2), /* MBOX_BUS_RESET */ + PACKB(2, 3), /* MBOX_STOP_QUEUE */ + PACKB(2, 3), /* MBOX_START_QUEUE */ + PACKB(2, 3), /* MBOX_SINGLE_STEP_QUEUE */ + PACKB(2, 3), /* MBOX_ABORT_QUEUE */ + PACKB(2, 4), /* MBOX_GET_DEV_QUEUE_STATUS */ + PACKB(0, 0), /* 0x001e */ + PACKB(1, 3), /* MBOX_GET_FIRMWARE_STATUS */ + PACKB(1, 2), /* MBOX_GET_INIT_SCSI_ID */ + PACKB(1, 2), /* MBOX_GET_SELECT_TIMEOUT */ + PACKB(1, 3), /* MBOX_GET_RETRY_COUNT */ + PACKB(1, 2), /* MBOX_GET_TAG_AGE_LIMIT */ + PACKB(1, 2), /* MBOX_GET_CLOCK_RATE */ + PACKB(1, 2), /* MBOX_GET_ACT_NEG_STATE */ + PACKB(1, 2), /* MBOX_GET_ASYNC_DATA_SETUP_TIME */ + PACKB(1, 3), /* MBOX_GET_PCI_PARAMS */ + PACKB(2, 4), /* MBOX_GET_TARGET_PARAMS */ + PACKB(2, 4), /* MBOX_GET_DEV_QUEUE_PARAMS */ + PACKB(0, 0), /* 0x002a */ + PACKB(0, 0), /* 0x002b */ + PACKB(0, 0), /* 0x002c */ + PACKB(0, 0), /* 0x002d */ + PACKB(0, 0), /* 0x002e */ + PACKB(0, 0), /* 0x002f */ + PACKB(2, 2), /* MBOX_SET_INIT_SCSI_ID */ + PACKB(2, 2), /* MBOX_SET_SELECT_TIMEOUT */ + PACKB(3, 3), /* MBOX_SET_RETRY_COUNT */ + PACKB(2, 2), /* MBOX_SET_TAG_AGE_LIMIT */ + PACKB(2, 2), /* MBOX_SET_CLOCK_RATE */ + PACKB(2, 2), /* MBOX_SET_ACTIVE_NEG_STATE */ + PACKB(2, 2), /* MBOX_SET_ASYNC_DATA_SETUP_TIME */ + PACKB(3, 3), /* MBOX_SET_PCI_CONTROL_PARAMS */ + PACKB(4, 4), /* MBOX_SET_TARGET_PARAMS */ + PACKB(4, 4), /* MBOX_SET_DEV_QUEUE_PARAMS */ + PACKB(0, 0), /* 0x003a */ + PACKB(0, 0), /* 0x003b */ + PACKB(0, 0), /* 0x003c */ + PACKB(0, 0), /* 0x003d */ + PACKB(0, 0), /* 0x003e */ + PACKB(0, 0), /* 0x003f */ + PACKB(1, 2), /* MBOX_RETURN_BIOS_BLOCK_ADDR */ + PACKB(6, 1), /* MBOX_WRITE_FOUR_RAM_WORDS */ + PACKB(2, 3) /* MBOX_EXEC_BIOS_IOCB */ +}; + +#define MAX_MBOX_COMMAND (sizeof(mbox_param)/sizeof(u_short)) + +struct host_param { + u_short fifo_threshold; + u_short host_adapter_enable; + u_short initiator_scsi_id; + u_short bus_reset_delay; + u_short retry_count; + u_short retry_delay; + u_short async_data_setup_time; + u_short req_ack_active_negation; + u_short data_line_active_negation; + u_short data_dma_burst_enable; + u_short command_dma_burst_enable; + u_short tag_aging; + u_short selection_timeout; + u_short max_queue_depth; +}; + +/* + * Device Flags: + * + * Bit Name + * --------- + * 7 Disconnect Privilege + * 6 Parity Checking + * 5 Wide Data Transfers + * 4 Syncronous Data Transfers + * 3 Tagged Queuing + * 2 Automatic Request Sense + * 1 Stop Queue on Check Condition + * 0 Renegotiate on Error + */ + +struct dev_param { + u_short device_flags; + u_short execution_throttle; + u_short synchronous_period; + u_short synchronous_offset; + u_short device_enable; +}; + +#define REQ_QUEUE_LEN 32 +#define RES_QUEUE_LEN 32 +#define QUEUE_ENTRY_LEN 64 + +struct isp1020_hostdata { + u_char irq; + u_char bus; + u_long io_base; + u_char revision; + u_char device_fn; + u_short res_queue_in_ptr; + u_short res_queue_out_ptr; + u_short req_queue_in_ptr; + u_short req_queue_out_ptr; + struct host_param host_param; + struct dev_param dev_param[16]; + char res_queue[RES_QUEUE_LEN][QUEUE_ENTRY_LEN]; + char req_queue[REQ_QUEUE_LEN][QUEUE_ENTRY_LEN]; +}; + +struct isp1020_hostdata *irq2host[16]; + +void isp1020_enable_irqs(struct isp1020_hostdata *); +void isp1020_disable_irqs(struct isp1020_hostdata *); +int isp1020_init(struct Scsi_Host *); +int isp1020_reset_hardware(struct isp1020_hostdata *); +int isp1020_get_defaults(struct isp1020_hostdata *); +int isp1020_set_defaults(struct isp1020_hostdata *); +int isp1020_load_parameters(struct isp1020_hostdata *); +int isp1020_mbox_command(struct isp1020_hostdata *, u_short []); +u_short isp1020_read_nvram_word(struct isp1020_hostdata *, u_short); +int isp1020_verify_nvram(struct isp1020_hostdata *); +void isp1020_print_status_entry(struct Status_Entry *); +void isp1020_print_scsi_cmd(Scsi_Cmnd *); +void isp1020_scsi_done(Scsi_Cmnd *); +int isp1020_return_status(struct Status_Entry *); +void isp1020_intr_handler(int, struct pt_regs *); + + +int isp1020_detect(Scsi_Host_Template *tmpt) +{ + int hosts = 0; + u_short index; + u_char bus, device_fn; + struct Scsi_Host *scsihost; + struct isp1020_hostdata *hostdata; + + ENTER("isp1020_detect"); + + if (pcibios_present() == 0) { + printk("qlogicisp : PCI bios not present\n"); + return 0; + } + + memset(irq2host, 0, sizeof(irq2host)); + + for (index = 0; pcibios_find_device(PCI_VENDOR_ID_QLOGIC, + PCI_DEVICE_ID_QLOGIC_ISP1020, index, &bus, &device_fn) == 0; + index++) { + + scsihost = scsi_register(tmpt, sizeof(struct isp1020_hostdata)); + hostdata = (struct isp1020_hostdata *) scsihost->hostdata; + + memset(hostdata, 0, sizeof(struct isp1020_hostdata)); + hostdata->bus = bus; + hostdata->device_fn = device_fn; + + if (isp1020_init(scsihost) || isp1020_reset_hardware(hostdata) +#if USE_NVRAM_DEFAULTS + || isp1020_get_defaults(hostdata) +#else + || isp1020_set_defaults(hostdata) +#endif /* USE_NVRAM_DEFAULTS */ + || isp1020_load_parameters(hostdata)) { + scsi_unregister(scsihost); + continue; + } + + scsihost->this_id = hostdata->host_param.initiator_scsi_id; + + if (request_irq(hostdata->irq, isp1020_intr_handler, 0, + "qlogicisp", NULL)) { + printk("qlogicisp : interrupt %d already in use\n", hostdata->irq); + scsi_unregister(scsihost); + continue; + } + + if (check_region(hostdata->io_base, 0xff)) { + printk("qlogicisp : i/o region 0x%04lx-0x%04lx already in use\n", + hostdata->io_base, hostdata->io_base + 0xff); + free_irq(hostdata->irq, NULL); + scsi_unregister(scsihost); + continue; + } + + request_region(hostdata->io_base, 0xff, "qlogicisp"); + irq2host[hostdata->irq] = hostdata; + + isp1020_enable_irqs(hostdata); + + hosts++; + } + + LEAVE("isp1020_detect"); + + return hosts; +} + + +int isp1020_release(struct Scsi_Host *host) +{ + struct isp1020_hostdata *hostdata; + + ENTER("isp1020_release"); + + hostdata = (struct isp1020_hostdata *) host->hostdata; + + outw(0x0, hostdata->io_base + PCI_INTF_CTL); + free_irq(hostdata->irq, NULL); + + release_region(hostdata->io_base, 0xff); + + LEAVE("isp1020_release"); + + return 0; +} + + +const char *isp1020_info(struct Scsi_Host *host) +{ + static char buf[80]; + struct isp1020_hostdata *hostdata; + + ENTER("isp1020_info"); + + hostdata = (struct isp1020_hostdata *) host->hostdata; + sprintf(buf, "QLogic ISP1020 SCSI on PCI bus %d, device %d, irq %d", + hostdata->bus, (hostdata->device_fn & 0xf8) >> 3, hostdata->irq); + + LEAVE("isp1020_info"); + + return buf; +} + + +#define REQ_QUEUE_DEPTH() \ + (hostdata->req_queue_in_ptr >= hostdata->req_queue_out_ptr \ + ? hostdata->req_queue_in_ptr - hostdata->req_queue_out_ptr \ + : (REQ_QUEUE_LEN - hostdata->req_queue_out_ptr) \ + + hostdata->req_queue_in_ptr) + + +int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *)) +{ + int i, *iptr, sg_count; + struct scatterlist *sg; + struct Command_Entry *cmd; + struct isp1020_hostdata *hostdata; + + ENTER("isp1020_queuecommand"); + + hostdata = (struct isp1020_hostdata *) Cmnd->host->hostdata; + Cmnd->scsi_done = done; + + DEBUG(isp1020_print_scsi_cmd(Cmnd);) + + hostdata->req_queue_out_ptr = inw(hostdata->io_base + MBOX4); + + if ((hostdata->req_queue_in_ptr + 1) % REQ_QUEUE_LEN == + hostdata->req_queue_out_ptr) { + printk("qlogicisp : request queue overflow\n"); + return 1; + } + + DEBUG(printk("qlogicisp : request queue depth %d\n", REQ_QUEUE_DEPTH())); + + cmd = (struct Command_Entry *) + &hostdata->req_queue[hostdata->req_queue_in_ptr][0]; + + memset(cmd, 0, sizeof(struct Command_Entry)); + + cmd->hdr.entry_type = ENTRY_COMMAND; + cmd->hdr.entry_cnt = 1; + + cmd->handle = (caddr_t) Cmnd; + cmd->target_lun = Cmnd->lun; + cmd->target_id = Cmnd->target; + cmd->cdb_length = Cmnd->cmd_len; + cmd->control_flags = CFLAG_READ | CFLAG_WRITE; + + for (i = 0; i < Cmnd->cmd_len; i++) + cmd->cdb[i] = Cmnd->cmnd[i]; + + if (Cmnd->use_sg) { + cmd->segment_cnt = sg_count = Cmnd->use_sg; + sg = (struct scatterlist *) Cmnd->request_buffer; + iptr = (int *) &cmd->dataseg0.d_base; + + for (i = 0; sg_count > 0; sg_count--, i++) { + *iptr++ = (int) sg[i].address; + *iptr++ = sg[i].length; + } + } + else { + cmd->dataseg0.d_base = (caddr_t) Cmnd->request_buffer; + cmd->dataseg0.d_count = (u_long) Cmnd->request_bufflen; + cmd->segment_cnt = 1; + } + + hostdata->req_queue_in_ptr = (hostdata->req_queue_in_ptr + 1) + % REQ_QUEUE_LEN; + + outw(hostdata->req_queue_in_ptr, hostdata->io_base + MBOX4); + + LEAVE("isp1020_queuecommand"); + + return 0; +} + + +#define RES_QUEUE_DEPTH() \ + (hostdata->res_queue_in_ptr >= hostdata->res_queue_out_ptr \ + ? hostdata->res_queue_in_ptr - hostdata->res_queue_out_ptr \ + : (RES_QUEUE_LEN - hostdata->res_queue_out_ptr) \ + + hostdata->res_queue_in_ptr) + + +int isp1020_abort(Scsi_Cmnd *Cmnd) +{ + u_short param[6]; + struct isp1020_hostdata *hostdata; + int return_status = SCSI_ABORT_SUCCESS; + + ENTER("isp1020_abort"); + + hostdata = (struct isp1020_hostdata *) Cmnd->host->hostdata; + + isp1020_disable_irqs(hostdata); + + DEBUG(printk("qlogicisp : response queue depth %d\n", RES_QUEUE_DEPTH())); + + param[0] = MBOX_ABORT; + param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun; + param[2] = (u_long) Cmnd >> 16; + param[3] = (u_long) Cmnd & 0xffff; + + isp1020_mbox_command(hostdata, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : scsi abort failure: %x\n", param[0]); + return_status = SCSI_ABORT_ERROR; + } + + isp1020_enable_irqs(hostdata); + + LEAVE("isp1020_abort"); + + return return_status; +} + + +int isp1020_reset(Scsi_Cmnd *Cmnd) +{ + u_short param[6]; + struct isp1020_hostdata *hostdata; + int return_status = SCSI_RESET_SUCCESS; + + ENTER("isp1020_reset"); + + hostdata = (struct isp1020_hostdata *) Cmnd->host->hostdata; + + param[0] = MBOX_BUS_RESET; + param[1] = hostdata->host_param.bus_reset_delay; + + isp1020_disable_irqs(hostdata); + + isp1020_mbox_command(hostdata, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : scsi bus reset failure: %x\n", param[0]); + return_status = SCSI_RESET_ERROR; + } + + isp1020_enable_irqs(hostdata); + + LEAVE("isp1020_reset"); + + return SCSI_RESET_SUCCESS; +} + + +int isp1020_biosparam(Disk *disk, int n, int ip[]) +{ + int size = disk->capacity; + + ENTER("isp1020_biosparam"); + + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + if (ip[2] > 1024) { + ip[0] = 255; + ip[1] = 63; + ip[2] = size / (ip[0] * ip[1]); + if (ip[2] > 1023) + ip[2] = 1023; + } + + LEAVE("isp1020_biosparam"); + + return 0; +} + + +int isp1020_reset_hardware(struct isp1020_hostdata *hostdata) +{ + u_short param[6]; + + ENTER("isp1020_reset_hardware"); + + outw(0x0001, hostdata->io_base + PCI_INTF_CTL); + outw(HCCR_RESET, hostdata->io_base + HOST_HCCR); + outw(HCCR_RELEASE, hostdata->io_base + HOST_HCCR); + outw(HCCR_BIOS_ENABLE, hostdata->io_base + HOST_HCCR); + + while (inw(hostdata->io_base + MBOX0)) + barrier(); + +#if DEBUG_ISP1020 + printk("qlogicisp : mbox 0 0x%04x \n", inw(hostdata->io_base + MBOX0)); + printk("qlogicisp : mbox 1 0x%04x \n", inw(hostdata->io_base + MBOX1)); + printk("qlogicisp : mbox 2 0x%04x \n", inw(hostdata->io_base + MBOX2)); + printk("qlogicisp : mbox 3 0x%04x \n", inw(hostdata->io_base + MBOX3)); + printk("qlogicisp : mbox 4 0x%04x \n", inw(hostdata->io_base + MBOX4)); + printk("qlogicisp : mbox 5 0x%04x \n", inw(hostdata->io_base + MBOX5)); +#endif /* DEBUG_ISP1020 */ + + DEBUG(printk("qlogicisp : loading risc ram\n");) + +#if RELOAD_FIRMWARE + { int i; + for (i = 0; i < risc_code_length01; i++) { + param[0] = MBOX_WRITE_RAM_WORD; + param[1] = risc_code_addr01 + i; + param[2] = risc_code01[i]; + + isp1020_mbox_command(hostdata, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : firmware load failure\n"); + return 1; + } + } + } +#endif /* RELOAD_FIRMEARE */ + + DEBUG(printk("qlogicisp : verifing checksum\n");) + + param[0] = MBOX_VERIFY_CHECKSUM; + param[1] = risc_code_addr01; + + isp1020_mbox_command(hostdata, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : ram checksum failure\n"); + return 1; + } + + DEBUG(printk("qlogicisp : executing firmware\n");) + + param[0] = MBOX_EXEC_FIRMWARE; + param[1] = risc_code_addr01; + + isp1020_mbox_command(hostdata, param); + + param[0] = MBOX_ABOUT_FIRMWARE; + + isp1020_mbox_command(hostdata, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : about firmware failure\n"); + return 1; + } + + DEBUG(printk("qlogicisp : firmware major revision %d\n", param[1]);) + DEBUG(printk("qlogicisp : firmware minor revision %d\n", param[2]);) + + LEAVE("isp1020_reset_hardware"); + + return 0; +} + + +int isp1020_init(struct Scsi_Host *sh) +{ + u_long io_base; + struct isp1020_hostdata *hostdata; + u_char bus, device_fn, revision, irq; + u_short vendor_id, device_id, command; + + ENTER("isp1020_init"); + + hostdata = (struct isp1020_hostdata *) sh->hostdata; + bus = hostdata->bus; + device_fn = hostdata->device_fn; + + if (pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id) + || pcibios_read_config_word(bus, device_fn, + PCI_DEVICE_ID, &device_id) + || pcibios_read_config_word(bus, device_fn, + PCI_COMMAND, &command) + || pcibios_read_config_dword(bus, device_fn, + PCI_BASE_ADDRESS_0, &io_base) + || pcibios_read_config_byte(bus, device_fn, + PCI_CLASS_REVISION, &revision) + || pcibios_read_config_byte(bus, device_fn, + PCI_INTERRUPT_LINE, &irq)) { + printk("qlogicisp : error reading PCI configuration\n"); + return 1; + } + + if (vendor_id != PCI_VENDOR_ID_QLOGIC) { + printk("qlogicisp : 0x%04x is not QLogic vendor ID\n", vendor_id); + return 1; + } + + if (device_id != PCI_DEVICE_ID_QLOGIC_ISP1020) { + printk("qlogicisp : 0x%04x does not match ISP1020 device id\n", + device_id); + return 1; + } + + if (command & PCI_COMMAND_IO && (io_base & 3) == 1) + io_base &= PCI_BASE_ADDRESS_IO_MASK; + else { + printk("qlogicisp : i/o mapping is disabled\n"); + return 1; + } + + if (!(command & PCI_COMMAND_MASTER)) { + printk("qlogicisp : bus mastering is disabled\n"); + return 1; + } + + if (revision != ISP1020_REV_ID) + printk("qlogicisp : warning : new isp1020 revision id\n"); + + if (inw(io_base + PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC + || inw(io_base + PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020) { + printk("qlogicisp : can't decode i/o address space\n"); + return 1; + } + + hostdata->io_base = io_base; + hostdata->revision = revision; + hostdata->irq = irq; + + LEAVE("isp1020_init"); + + return 0; +} + + +int isp1020_get_defaults(struct isp1020_hostdata *hostdata) +{ + int i; + u_short value; + + ENTER("isp1020_get_defaults"); + + if (!isp1020_verify_nvram(hostdata)) { + printk("qlogicisp : nvram checksum failure\n"); + return 1; + } + + value = isp1020_read_nvram_word(hostdata, 2); + hostdata->host_param.fifo_threshold = (value >> 8) & 0x03; + hostdata->host_param.host_adapter_enable = (value >> 11) & 0x01; + hostdata->host_param.initiator_scsi_id = (value >> 12) & 0x0f; + + value = isp1020_read_nvram_word(hostdata, 3); + hostdata->host_param.bus_reset_delay = value & 0xff; + hostdata->host_param.retry_count = value >> 8; + + value = isp1020_read_nvram_word(hostdata, 4); + hostdata->host_param.retry_delay = value & 0xff; + hostdata->host_param.async_data_setup_time = (value >> 8) & 0x0f; + hostdata->host_param.req_ack_active_negation = (value >> 12) & 0x01; + hostdata->host_param.data_line_active_negation = (value >> 13) & 0x01; + hostdata->host_param.data_dma_burst_enable = (value >> 14) & 0x01; + hostdata->host_param.command_dma_burst_enable = (value >> 15); + + value = isp1020_read_nvram_word(hostdata, 5); + hostdata->host_param.tag_aging = value & 0xff; + + value = isp1020_read_nvram_word(hostdata, 6); + hostdata->host_param.selection_timeout = value & 0xffff; + + value = isp1020_read_nvram_word(hostdata, 7); + hostdata->host_param.max_queue_depth = value & 0xffff; + +#if DEBUG_ISP1020_SETUP + printk("qlogicisp : fifo threshold=%d\n", + hostdata->host_param.fifo_threshold); + printk("qlogicisp : initiator scsi id=%d\n", + hostdata->host_param.initiator_scsi_id); + printk("qlogicisp : bus reset delay=%d\n", + hostdata->host_param.bus_reset_delay); + printk("qlogicisp : retry count=%d\n", + hostdata->host_param.retry_count); + printk("qlogicisp : retry delay=%d\n", + hostdata->host_param.retry_delay); + printk("qlogicisp : async data setup time=%d\n", + hostdata->host_param.async_data_setup_time); + printk("qlogicisp : req/ack active negation=%d\n", + hostdata->host_param.req_ack_active_negation); + printk("qlogicisp : data line active negation=%d\n", + hostdata->host_param.data_line_active_negation); + printk("qlogicisp : data DMA burst enable=%d\n", + hostdata->host_param.data_dma_burst_enable); + printk("qlogicisp : command DMA burst enable=%d\n", + hostdata->host_param.command_dma_burst_enable); + printk("qlogicisp : tag age limit=%d\n", + hostdata->host_param.tag_aging); + printk("qlogicisp : selection timeout limit=%d\n", + hostdata->host_param.selection_timeout); + printk("qlogicisp : max queue depth=%d\n", + hostdata->host_param.max_queue_depth); +#endif /* DEBUG_ISP1020_SETUP */ + + for (i = 0; i < 16; i++) { + + value = isp1020_read_nvram_word(hostdata, 14 + i * 3); + hostdata->dev_param[i].device_flags = value & 0xff; + hostdata->dev_param[i].execution_throttle = value >> 8; + + value = isp1020_read_nvram_word(hostdata, 15 + i * 3); + hostdata->dev_param[i].synchronous_period = value & 0xff; + hostdata->dev_param[i].synchronous_offset = (value >> 8) & 0x0f; + hostdata->dev_param[i].device_enable = (value >> 12) & 0x01; + +#if DEBUG_ISP1020_SETUP + printk("qlogicisp : target 0x%02x\n", i); + printk("qlogicisp : device flags=0x%02x\n", + hostdata->dev_param[i].device_flags); + printk("qlogicisp : execution throttle=%d\n", + hostdata->dev_param[i].execution_throttle); + printk("qlogicisp : synchronous period=%d\n", + hostdata->dev_param[i].synchronous_period); + printk("qlogicisp : synchronous offset=%d\n", + hostdata->dev_param[i].synchronous_offset); + printk("qlogicisp : device enable=%d\n", + hostdata->dev_param[i].device_enable); +#endif /* DEBUG_ISP1020_SETUP */ + } + + LEAVE("isp1020_get_defaults"); + + return 0; +} + + +int isp1020_set_defaults(struct isp1020_hostdata *hostdata) +{ + int i; + + ENTER("isp1020_set_defaults"); + + hostdata->host_param.fifo_threshold = 2; + hostdata->host_param.host_adapter_enable = 1; + hostdata->host_param.initiator_scsi_id = 7; + hostdata->host_param.bus_reset_delay = 3; + hostdata->host_param.retry_count = 0; + hostdata->host_param.retry_delay = 0; + hostdata->host_param.async_data_setup_time = 6; + hostdata->host_param.req_ack_active_negation = 1; + hostdata->host_param.data_line_active_negation = 1; + hostdata->host_param.data_dma_burst_enable = 1; + hostdata->host_param.command_dma_burst_enable = 1; + hostdata->host_param.tag_aging = 8; + hostdata->host_param.selection_timeout = 250; + hostdata->host_param.max_queue_depth = 256; + + for (i = 0; i < 16; i++) { + hostdata->dev_param[i].device_flags = 0xc4; + hostdata->dev_param[i].execution_throttle = 16; + hostdata->dev_param[i].synchronous_period = 25; + hostdata->dev_param[i].synchronous_offset = 12; + hostdata->dev_param[i].device_enable = 1; + } + + LEAVE("isp1020_set_defaults"); + + return 0; +} + + +int isp1020_load_parameters(struct isp1020_hostdata *hostdata) +{ + int i, k; + u_long queue_addr; + u_short param[6]; + u_short isp_cfg1; + + ENTER("isp1020_load_parameters"); + + outw(hostdata->host_param.fifo_threshold, hostdata->io_base + ISP_CFG1); + + param[0] = MBOX_SET_INIT_SCSI_ID; + param[1] = hostdata->host_param.initiator_scsi_id; + + isp1020_mbox_command(hostdata, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : set initiator id failure\n"); + return 1; + } + + param[0] = MBOX_SET_RETRY_COUNT; + param[1] = hostdata->host_param.retry_count; + param[2] = hostdata->host_param.retry_delay; + + isp1020_mbox_command(hostdata, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : set retry count failure\n"); + return 1; + } + + param[0] = MBOX_SET_ASYNC_DATA_SETUP_TIME; + param[1] = hostdata->host_param.async_data_setup_time; + + isp1020_mbox_command(hostdata, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : async data setup time failure\n"); + return 1; + } + + param[0] = MBOX_SET_ACTIVE_NEG_STATE; + param[1] = (hostdata->host_param.req_ack_active_negation << 4) + | (hostdata->host_param.data_line_active_negation << 5); + + isp1020_mbox_command(hostdata, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : set active negation state failure\n"); + return 1; + } + + param[0] = MBOX_SET_PCI_CONTROL_PARAMS; + param[1] = hostdata->host_param.data_dma_burst_enable << 1; + param[2] = hostdata->host_param.command_dma_burst_enable << 1; + + isp1020_mbox_command(hostdata, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : set pci control parameter failure\n"); + return 1; + } + + isp_cfg1 = inw(hostdata->io_base + ISP_CFG1); + + if (hostdata->host_param.data_dma_burst_enable + || hostdata->host_param.command_dma_burst_enable) + isp_cfg1 |= 0x0004; + else + isp_cfg1 &= 0xfffb; + + outw(isp_cfg1, hostdata->io_base + ISP_CFG1); + + param[0] = MBOX_SET_TAG_AGE_LIMIT; + param[1] = hostdata->host_param.tag_aging; + + isp1020_mbox_command(hostdata, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : set tag age limit failure\n"); + return 1; + } + + param[0] = MBOX_SET_SELECT_TIMEOUT; + param[1] = hostdata->host_param.selection_timeout; + + isp1020_mbox_command(hostdata, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : set selection timeout failure\n"); + return 1; + } + + for (i = 0; i < 16; i++) { + + if (!hostdata->dev_param[i].device_enable) + continue; + + param[0] = MBOX_SET_TARGET_PARAMS; + param[1] = i << 8; + param[2] = hostdata->dev_param[i].device_flags << 8; + param[3] = (hostdata->dev_param[i].synchronous_offset << 8) + | hostdata->dev_param[i].synchronous_period; + + isp1020_mbox_command(hostdata, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : set target parameter failure\n"); + return 1; + } + + for (k = 0; k < 8; k++) { + + param[0] = MBOX_SET_DEV_QUEUE_PARAMS; + param[1] = (i << 8) | k; + param[2] = hostdata->host_param.max_queue_depth; + param[3] = hostdata->dev_param[i].execution_throttle; + + isp1020_mbox_command(hostdata, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : set device queue parameter failure\n"); + return 1; + } + } + } + + queue_addr = (u_long) &hostdata->res_queue[0][0]; + + param[0] = MBOX_INIT_RES_QUEUE; + param[1] = RES_QUEUE_LEN; + param[2] = (u_short) (queue_addr >> 16); + param[3] = (u_short) (queue_addr & 0xffff); + param[4] = 0; + param[5] = 0; + + isp1020_mbox_command(hostdata, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : set response queue failure\n"); + return 1; + } + + queue_addr = (u_long) &hostdata->req_queue[0][0]; + + param[0] = MBOX_INIT_REQ_QUEUE; + param[1] = REQ_QUEUE_LEN; + param[2] = (u_short) (queue_addr >> 16); + param[3] = (u_short) (queue_addr & 0xffff); + param[4] = 0; + + isp1020_mbox_command(hostdata, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : set request queue failure\n"); + return 1; + } + + LEAVE("isp1020_load_parameters"); + + return 0; +} + + +int isp1020_mbox_command(struct isp1020_hostdata *hostdata, u_short param[]) +{ + if (mbox_param[param[0]] == 0) + return 1; + + while (inw(hostdata->io_base + HOST_HCCR) & 0x0080) + barrier(); + + switch(mbox_param[param[0]] >> 4) { + case 6: outw(param[5], hostdata->io_base + MBOX5); + case 5: outw(param[4], hostdata->io_base + MBOX4); + case 4: outw(param[3], hostdata->io_base + MBOX3); + case 3: outw(param[2], hostdata->io_base + MBOX2); + case 2: outw(param[1], hostdata->io_base + MBOX1); + case 1: outw(param[0], hostdata->io_base + MBOX0); + } + + outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR); + outw(0x0, hostdata->io_base + PCI_SEMAPHORE); + + outw(HCCR_SET_HOST_INTR, hostdata->io_base + HOST_HCCR); + + while (!(inw(hostdata->io_base + PCI_INTF_STS) & 0x04)) + barrier(); + + while (inw(hostdata->io_base + MBOX0) == 0x04) + barrier(); + + outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR); + outw(0x0, hostdata->io_base + PCI_SEMAPHORE); + + switch(mbox_param[param[0]] & 0xf) { + case 6: param[5] = inw(hostdata->io_base + MBOX5); + case 5: param[4] = inw(hostdata->io_base + MBOX4); + case 4: param[3] = inw(hostdata->io_base + MBOX3); + case 3: param[2] = inw(hostdata->io_base + MBOX2); + case 2: param[1] = inw(hostdata->io_base + MBOX1); + case 1: param[0] = inw(hostdata->io_base + MBOX0); + } + + return 0; +} + + +#define RESPONSE_QUEUE_UPDATE 0x01 + +void isp1020_intr_handler(int irq, struct pt_regs *regs) +{ + Scsi_Cmnd *Cmnd; + struct Status_Entry *sts; + struct Marker_Entry *marker; + u_short status, add_marker = 0; + struct isp1020_hostdata *hostdata; + + ENTER_INTR("isp1020_intr_handler"); + + if ((hostdata = irq2host[irq]) == NULL) { + printk("qlogicisp : unexpected interrupt on line %d\n", irq); + return; + } + + DEBUG_INTR(printk("qlogicisp : interrupt on line %d\n", irq);) + + while (!(inw(hostdata->io_base + PCI_INTF_STS) & 0x04)) + barrier(); + + hostdata->res_queue_in_ptr = inw(hostdata->io_base + MBOX5); + outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR); + status = inw(hostdata->io_base + PCI_SEMAPHORE); + + if ((status & RESPONSE_QUEUE_UPDATE) == 0) { + + DEBUG_INTR(printk("qlogicisp : response queue update\n");) + DEBUG_INTR(printk("qlogicisp : response queue depth %d\n", + RES_QUEUE_DEPTH());) + + while (hostdata->res_queue_out_ptr != hostdata->res_queue_in_ptr) { + + sts = (struct Status_Entry *) + &hostdata->res_queue[hostdata->res_queue_out_ptr][0]; + + Cmnd = (Scsi_Cmnd *) sts->handle; + + if (sts->completion_status == CS_RESET_OCCURRED + || sts->completion_status == CS_ABORTED + || (sts->status_flags & STF_BUS_RESET)) + add_marker++; + + if (sts->state_flags & SF_GOT_SENSE) + memcpy(Cmnd->sense_buffer, sts->req_sense_data, + sizeof(Cmnd->sense_buffer)); + + DEBUG_INTR(isp1020_print_status_entry(sts);) + + if (sts->hdr.entry_type == ENTRY_STATUS) + Cmnd->result = isp1020_return_status(sts); + else + Cmnd->result = DID_ERROR << 16; + + hostdata->res_queue_out_ptr = (hostdata->res_queue_out_ptr + 1) + % RES_QUEUE_LEN; + + outw(hostdata->res_queue_out_ptr, hostdata->io_base + MBOX5); + + (Cmnd->scsi_done)(Cmnd); + } + } + else { + + DEBUG_INTR(printk("qlogicisp : mbox completion\n");) + + status = inw(hostdata->io_base + MBOX0); + outw(0x0, hostdata->io_base + PCI_SEMAPHORE); + + DEBUG_INTR(printk("qlogicisp : mbox completion status: %x\n", status);) + + switch (status) { + case ASYNC_SCSI_BUS_RESET: + case EXECUTION_TIMEOUT_RESET: + add_marker++; + break; + case INVALID_COMMAND: + case HOST_INTERFACE_ERROR: + case COMMAND_ERROR: + case COMMAND_PARAM_ERROR: + printk("qlogicisp : bad mailbox return status\n"); + break; + } + } + + if (add_marker) { + + DEBUG_INTR(printk("qlogicisp : adding marker entry\n");) + + if ((hostdata->req_queue_in_ptr + 1) % REQ_QUEUE_LEN + == hostdata->req_queue_out_ptr) { + printk("qlogicisp : request queue overflow\n"); + return; + } + + marker = (struct Marker_Entry *) + &hostdata->req_queue[hostdata->req_queue_in_ptr][0]; + + memset(marker, 0, sizeof(struct Marker_Entry)); + + marker->hdr.entry_type = ENTRY_MARKER; + marker->hdr.entry_cnt = 1; + marker->modifier = SYNC_ALL; + + hostdata->req_queue_in_ptr = (hostdata->req_queue_in_ptr + 1) + % REQ_QUEUE_LEN; + + outw(hostdata->req_queue_in_ptr, hostdata->io_base + MBOX4); + } + + LEAVE_INTR("isp1020_intr_handler"); +} + + +#define NVRAM_DELAY() { \ + int counter = 0; while (counter++ < 0xc8) barrier(); } + + +u_short isp1020_read_nvram_word(struct isp1020_hostdata *hostdata, u_short byte) +{ + int i; + u_short value, output, input; + + byte &= 0x3f; byte |= 0x0180; + + for (i = 8; i >= 0; i--) { + output = ((byte >> i) & 0x1) ? 0x4 : 0x0; + outw(output | 0x2, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); + outw(output | 0x3, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); + outw(output | 0x2, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); + } + + for (i = 0xf, value = 0; i >= 0; i--) { + value = value << 0x1; + outw(0x3, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); + input = inw(hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); + outw(0x2, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); + if (input & 0x8) value |= 0x1; + } + + outw(0x0, hostdata->io_base + PCI_NVRAM); + + return(value); +} + +#define ISP1020_NVRAM_LEN 0x40 +#define ISP1020_NVRAM_SIG1 0x5349 +#define ISP1020_NVRAM_SIG2 0x2050 + +int isp1020_verify_nvram(struct isp1020_hostdata *hostdata) +{ + int i; + u_short value; + u_char checksum = 0; + + for (i = 0; i < ISP1020_NVRAM_LEN; i++) { + value = isp1020_read_nvram_word(hostdata, i); + + switch (i) { + case 0: + if (value != ISP1020_NVRAM_SIG1) return 0; + break; + case 1: + if (value != ISP1020_NVRAM_SIG2) return 0; + break; + case 2: + if ((value & 0xff) != 0x02) return 0; + break; + } + checksum += value & 0xff; + checksum += value >> 8; + } + + return (checksum == 0); +} + + +void isp1020_enable_irqs(struct isp1020_hostdata *hostdata) +{ + outw(0x6, hostdata->io_base + PCI_INTF_CTL); +} + + +void isp1020_disable_irqs(struct isp1020_hostdata *hostdata) +{ + outw(0x0, hostdata->io_base + PCI_INTF_CTL); +} + + +#if DEBUG_ISP1020_INTR + +void isp1020_print_status_entry(struct Status_Entry *status) +{ + int i; + + printk("qlogicisp : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", + status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags); + printk("qlogicisp : scsi status = 0x%04x, compeltion status = 0x%04x\n", + status->scsi_status, status->completion_status); + printk("qlogicisp : state flags = 0x%04x, status flags = 0x%04x\n", + status->state_flags, status->status_flags); + printk("qlogicisp : time = 0x%04x, request sense length = 0x%04x\n", + status->time, status->req_sense_len); + printk("qlogicisp : residual transfer length = 0x%08lx\n", status->residual); + + for (i = 0; i < status->req_sense_len; i++) + printk("qlogicisp : sense data = 0x%02x\n", status->req_sense_data[i]); +} + +#endif /* DEBUG_ISP1020_INTR */ + + +#if DEBUG_ISP1020 + +void isp1020_print_scsi_cmd(Scsi_Cmnd *cmd) +{ + int i; + + printk("qlogicisp : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", + cmd->target, cmd->lun, cmd->cmd_len); + printk("qlogicisp : command = "); + for (i = 0; i < cmd->cmd_len; i++) + printk("0x%02x ", cmd->cmnd[i]); + printk("\n"); +} + +#endif /* DEBUG_ISP1020 */ + + +int isp1020_return_status(struct Status_Entry *sts) +{ + int host_status = DID_ERROR; +#if DEBUG_ISP1020_INTR + static char *reason[] = { + "DID_OK", + "DID_NO_CONNECT", + "DID_BUS_BUSY", + "DID_TIME_OUT", + "DID_BAD_TARGET", + "DID_ABORT", + "DID_PARITY", + "DID_ERROR", + "DID_RESET", + "DID_BAD_INTR" + }; +#endif /* DEBUG_ISP1020_INTR */ + + ENTER("isp1020_return_status"); + + DEBUG(printk("qlogicisp : completion status = 0x%04x\n", + sts->completion_status);) + + switch(sts->completion_status) { + case CS_COMPLETE: + host_status = DID_OK; + break; + case CS_INCOMPLETE: + if (!(sts->state_flags & SF_GOT_BUS)) + host_status = DID_NO_CONNECT; + else if (!(sts->state_flags & SF_GOT_TARGET)) + host_status = DID_BAD_TARGET; + else if (!(sts->state_flags & SF_SENT_CDB)) + host_status = DID_ERROR; + else if (!(sts->state_flags & SF_TRANSFERRED_DATA)) + host_status = DID_ERROR; + else if (!(sts->state_flags & SF_GOT_STATUS)) + host_status = DID_ERROR; + else if (!(sts->state_flags & SF_GOT_SENSE)) + host_status = DID_ERROR; + break; + case CS_DMA_ERROR: + case CS_TRANSPORT_ERROR: + host_status = DID_ERROR; + break; + case CS_RESET_OCCURRED: + host_status = DID_RESET; + break; + case CS_ABORTED: + host_status = DID_ABORT; + break; + case CS_TIMEOUT: + host_status = DID_TIME_OUT; + break; + case CS_DATA_OVERRUN: + case CS_COMMAND_OVERRUN: + case CS_STATUS_OVERRUN: + case CS_BAD_MESSAGE: + case CS_NO_MESSAGE_OUT: + case CS_EXT_ID_FAILED: + case CS_IDE_MSG_FAILED: + case CS_ABORT_MSG_FAILED: + case CS_NOP_MSG_FAILED: + case CS_PARITY_ERROR_MSG_FAILED: + case CS_DEVICE_RESET_MSG_FAILED: + case CS_ID_MSG_FAILED: + case CS_UNEXP_BUS_FREE: + host_status = DID_ERROR; + break; + case CS_DATA_UNDERRUN: + host_status = DID_OK; + break; + default: + printk("qlogicisp : unknown completion status 0x%04x\n", + sts->completion_status); + host_status = DID_ERROR; + break; + } + + DEBUG_INTR(printk("qlogicisp : host status (%s) scsi status %x\n", + reason[host_status], sts->scsi_status);) + + LEAVE("isp1020_return_status"); + + return (sts->scsi_status & STATUS_MASK) | (host_status << 16); +} + +#if MODULE +Scsi_Host_Template driver_template = ISP1020; + +#include "scsi_module.c" +#endif /* MODULE */ diff --git a/drivers/scsi/qlogicisp.h b/drivers/scsi/qlogicisp.h new file mode 100644 index 000000000000..c64d172ad005 --- /dev/null +++ b/drivers/scsi/qlogicisp.h @@ -0,0 +1,82 @@ +/* + * QLogic ISP1020 Intelligent SCSI Processor Driver (PCI) + * Written by Erik H. Moe, ehm@cris.com + * Copyright 1995, Erik H. Moe + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +/* Renamed and updated to 1.3.x by Michael Griffith */ + +/* + * $Date: 1995/09/22 02:32:56 $ + * $Revision: 0.5 $ + * + * $Log: isp1020.h,v $ + * Revision 0.5 1995/09/22 02:32:56 root + * do auto request sense + * + * Revision 0.4 1995/08/07 04:48:28 root + * supply firmware with driver. + * numerous bug fixes/general cleanup of code. + * + * Revision 0.3 1995/07/16 16:17:16 root + * added reset/abort code. + * + * Revision 0.2 1995/06/29 03:19:43 root + * fixed biosparam. + * added queue protocol. + * + * Revision 0.1 1995/06/25 01:56:13 root + * Initial release. + * + */ + +#ifndef _QLOGICISP_H +#define _QLOGICISP_H + +int isp1020_detect(Scsi_Host_Template *); +int isp1020_release(struct Scsi_Host *); +const char * isp1020_info(struct Scsi_Host *); +int isp1020_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +int isp1020_abort(Scsi_Cmnd *); +int isp1020_reset(Scsi_Cmnd *); +int isp1020_biosparam(Disk *, int, int[]); + +#ifndef NULL +#define NULL (0) +#endif + +#define QLOGICISP { \ + /* next */ NULL, \ + /* usage_count */ NULL, \ + /* proc dir */ NULL, \ + /* procfs info */ NULL, \ + /* name */ NULL, \ + /* detect */ isp1020_detect, \ + /* release */ isp1020_release, \ + /* info */ isp1020_info, \ + /* command */ NULL, \ + /* queuecommand */ isp1020_queuecommand, \ + /* abort */ isp1020_abort, \ + /* reset */ isp1020_reset, \ + /* slave_attach */ NULL, \ + /* bios_param */ isp1020_biosparam, \ + /* can_queue */ 8, \ + /* this_id */ -1, \ + /* sg_tablesize */ 4, \ + /* cmd_per_lun */ 1, \ + /* present */ 0, \ + /* unchecked_isa_dma */ 0, \ + /* use_clustering */ DISABLE_CLUSTERING \ +} + +#endif /* _QLOGICISP_H */ diff --git a/drivers/scsi/qlogicisp_asm.c b/drivers/scsi/qlogicisp_asm.c new file mode 100644 index 000000000000..7ab9189bc9ce --- /dev/null +++ b/drivers/scsi/qlogicisp_asm.c @@ -0,0 +1,1273 @@ +/* + * Version 2.02 (10:42 June 16, 1995) + */ + +unsigned short risc_code_version = 2*1024+02; + +unsigned short risc_code_addr01 = 0x1000 ; + +#if RELOAD_FIRMWARE + +unsigned short risc_code01[] = { + 0x0078, 0x1041, 0x0000, 0x2744, 0x0000, 0x2043, 0x4f50, 0x5952, + 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31, + 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320, + 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, 0x5350, + 0x3130, 0x3230, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056, + 0x6572, 0x7369, 0x6f6e, 0x2030, 0x322e, 0x3032, 0x2020, 0x2043, + 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, 0x3030, 0x2050, + 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, 0x3030, 0x2020, + 0x2400, 0x20b9, 0x1212, 0x2071, 0x0010, 0x70c3, 0x0004, 0x20c9, + 0x42ff, 0x2089, 0x1159, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, + 0x2020, 0x70d3, 0x0002, 0x3f00, 0x70d6, 0x20c1, 0x0008, 0x2019, + 0x0000, 0x2009, 0xfeff, 0x2100, 0x200b, 0xa5a5, 0xa1ec, 0x7fff, + 0x2d64, 0x206b, 0x0a0a, 0xaddc, 0x3fff, 0x2b54, 0x205b, 0x5050, + 0x2114, 0xa286, 0xa5a5, 0x0040, 0x10b3, 0xa386, 0x000f, 0x0040, + 0x1079, 0x2c6a, 0x2a5a, 0x20c1, 0x0000, 0x2019, 0x000f, 0x0078, + 0x1059, 0x2c6a, 0x2a5a, 0x20c1, 0x0008, 0x2009, 0x7fff, 0x2148, + 0x2944, 0x204b, 0x0a0a, 0xa9bc, 0x3fff, 0x2734, 0x203b, 0x5050, + 0x2114, 0xa286, 0x0a0a, 0x0040, 0x109d, 0x284a, 0x263a, 0x20c1, + 0x0004, 0x2009, 0x3fff, 0x2134, 0x200b, 0x5050, 0x2114, 0xa286, + 0x5050, 0x0040, 0x109e, 0x0078, 0x1161, 0x284a, 0x263a, 0x98c0, + 0xa188, 0x1000, 0x212c, 0x200b, 0xa5a5, 0x2114, 0xa286, 0xa5a5, + 0x0040, 0x10b0, 0x250a, 0xa18a, 0x1000, 0x98c1, 0x0078, 0x10b5, + 0x250a, 0x0078, 0x10b5, 0x2c6a, 0x2a5a, 0x2130, 0xa18a, 0x0040, + 0x2128, 0xa1a2, 0x3800, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, + 0x8424, 0xa192, 0x4300, 0x2009, 0x0000, 0x2001, 0x002f, 0x1078, + 0x19ee, 0x2218, 0x2079, 0x3800, 0x2fa0, 0x2408, 0x2011, 0x0000, + 0x20a9, 0x0040, 0x42a4, 0x8109, 0x00c0, 0x10d0, 0x7eda, 0x7dce, + 0x8528, 0x7dca, 0x7cd2, 0x7bd6, 0x2031, 0x0030, 0x78b3, 0x0101, + 0x780b, 0x0002, 0x780f, 0x0002, 0x784f, 0x0003, 0x2069, 0x3840, + 0x681b, 0x0028, 0x6807, 0x0007, 0x680b, 0x00fa, 0x680f, 0x0008, + 0x6813, 0x0005, 0x681f, 0x0000, 0x6823, 0x0006, 0x6817, 0x0008, + 0x6827, 0x0000, 0x2069, 0x3900, 0x2011, 0x0020, 0x2009, 0x0010, + 0x680b, 0x0c19, 0x680f, 0x0019, 0x6803, 0xfd00, 0x6807, 0x0018, + 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004, 0x8109, 0x00c0, + 0x1100, 0x2069, 0x3980, 0x20a9, 0x0080, 0x680b, 0x0040, 0x7bd8, + 0xa386, 0xfeff, 0x00c0, 0x1122, 0x6817, 0x0100, 0x681f, 0x0064, + 0x0078, 0x1126, 0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, + 0x0070, 0x112c, 0x0078, 0x1115, 0x1078, 0x1c93, 0x1078, 0x3266, + 0x1078, 0x182c, 0x1078, 0x3706, 0x3200, 0xa085, 0x000d, 0x2090, + 0x70c3, 0x0000, 0x0090, 0x1143, 0x70c0, 0xa086, 0x0002, 0x00c0, + 0x1143, 0x1078, 0x1272, 0x1078, 0x1184, 0x78b0, 0xa005, 0x00c0, + 0x114f, 0x1078, 0x1a17, 0x0068, 0x1153, 0x1078, 0x1bed, 0x0068, + 0x1153, 0x1078, 0x191f, 0x00e0, 0x1143, 0x1078, 0x35a4, 0x0078, + 0x1143, 0x1161, 0x1163, 0x1e39, 0x1e39, 0x32c6, 0x32c6, 0x1e39, + 0x1e39, 0x0078, 0x1161, 0x0078, 0x1163, 0x0078, 0x1165, 0x0078, + 0x1167, 0x2009, 0x0022, 0x2104, 0xa086, 0x4000, 0x0040, 0x117f, + 0x7008, 0x800b, 0x00c8, 0x117f, 0x7007, 0x0002, 0xa08c, 0x0060, + 0x00c0, 0x1180, 0xa084, 0x0008, 0x0040, 0x117f, 0x087a, 0x097a, + 0x70c3, 0x4002, 0x0078, 0x1275, 0x0068, 0x11ef, 0x2061, 0x0000, + 0x6018, 0xa084, 0x0001, 0x00c0, 0x11ef, 0x7814, 0xa005, 0x00c0, + 0x1195, 0x0010, 0x11f0, 0x0078, 0x11ef, 0x2009, 0x3868, 0x2104, + 0xa005, 0x00c0, 0x11ef, 0x2009, 0x3871, 0x200b, 0x0000, 0x7914, + 0xa186, 0x0042, 0x00c0, 0x11ba, 0x7816, 0x2009, 0x386f, 0x2164, + 0x200b, 0x0000, 0x6018, 0x70c6, 0x6014, 0x70ca, 0x611c, 0xa18c, + 0xff00, 0x6020, 0xa084, 0x00ff, 0xa105, 0x70ce, 0x1078, 0x181e, + 0x0078, 0x11ed, 0x7814, 0xa086, 0x0018, 0x00c0, 0x11c1, 0x1078, + 0x15ce, 0x7817, 0x0000, 0x2009, 0x386f, 0x2104, 0xa065, 0x0040, + 0x11dd, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x187e, 0x0c7f, 0x609f, + 0x0000, 0x1078, 0x1695, 0x2009, 0x001c, 0x6087, 0x0103, 0x1078, + 0x17a5, 0x00c0, 0x11e9, 0x1078, 0x181e, 0x2009, 0x386f, 0x200b, + 0x0000, 0x2009, 0x3869, 0x2104, 0x200b, 0x0000, 0xa005, 0x0040, + 0x11ed, 0x2001, 0x4005, 0x0078, 0x1274, 0x0078, 0x1272, 0x007c, + 0x70c3, 0x0000, 0x70c7, 0x0000, 0x70cb, 0x0000, 0x70cf, 0x0000, + 0x70c0, 0xa0bc, 0xffc0, 0x00c0, 0x1240, 0x2038, 0x0079, 0x1200, + 0x1272, 0x12cd, 0x1291, 0x12cd, 0x1336, 0x1336, 0x1288, 0x16a9, + 0x1341, 0x1280, 0x1295, 0x1297, 0x1299, 0x129b, 0x16ae, 0x1280, + 0x1353, 0x137e, 0x15e6, 0x16a3, 0x129d, 0x1546, 0x1568, 0x157e, + 0x159b, 0x1503, 0x1511, 0x1525, 0x1539, 0x13f1, 0x1280, 0x139f, + 0x13a5, 0x13aa, 0x13af, 0x13b5, 0x13ba, 0x13bf, 0x13c4, 0x13c9, + 0x13cd, 0x13e2, 0x13ee, 0x1280, 0x1280, 0x1280, 0x1280, 0x13fd, + 0x1406, 0x1415, 0x143b, 0x1445, 0x144c, 0x1472, 0x1481, 0x1490, + 0x14a2, 0x14e3, 0x14f3, 0x1280, 0x1280, 0x1280, 0x1280, 0x14f8, + 0xa0bc, 0xffa0, 0x00c0, 0x1280, 0x2038, 0xa084, 0x001f, 0x0079, + 0x1249, 0x16c5, 0x16c8, 0x16d8, 0x1754, 0x178d, 0x1280, 0x1280, + 0x1280, 0x1280, 0x1280, 0x1280, 0x1280, 0x1280, 0x1280, 0x1280, + 0x1280, 0x12c3, 0x132c, 0x1349, 0x1374, 0x15dc, 0x1280, 0x1280, + 0x1280, 0x1280, 0x1280, 0x1280, 0x1280, 0x1280, 0x1280, 0x1280, + 0x1280, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0078, 0x1274, 0x73ce, + 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0068, 0x1275, 0x2061, + 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x007c, + 0x70c3, 0x4001, 0x0078, 0x1275, 0x70c3, 0x4006, 0x0078, 0x1275, + 0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0078, + 0x1272, 0x70c4, 0x70c3, 0x0004, 0x007a, 0x0078, 0x1272, 0x0078, + 0x1272, 0x0078, 0x1272, 0x0078, 0x1272, 0x2091, 0x8000, 0x70c3, + 0x0000, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, + 0x0002, 0x3f00, 0x70d6, 0x2079, 0x0000, 0x781b, 0x0001, 0x2031, + 0x0030, 0x2059, 0x1000, 0x2029, 0x0457, 0x2051, 0x0470, 0x2061, + 0x0472, 0x20b9, 0xffff, 0x20c1, 0x0000, 0x2091, 0x5000, 0x2091, + 0x4080, 0x0078, 0x0455, 0x1078, 0x198c, 0x00c0, 0x1284, 0x75d8, + 0x74dc, 0x75da, 0x74de, 0x0078, 0x12d0, 0x2029, 0x0000, 0x2520, + 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x20a0, 0x2098, 0x2031, 0x0030, + 0x81ff, 0x0040, 0x1272, 0x7007, 0x0004, 0x731a, 0x721e, 0x7422, + 0x7526, 0x2051, 0x0012, 0x2049, 0x130b, 0x2041, 0x1272, 0x7003, + 0x0002, 0xa786, 0x0001, 0x0040, 0x12f3, 0xa786, 0x0050, 0x0040, + 0x12f3, 0x0078, 0x12f9, 0x2049, 0x1318, 0x2041, 0x1324, 0x7003, + 0x0003, 0x7017, 0x0000, 0x810b, 0x7112, 0x00c8, 0x1301, 0x7017, + 0x0001, 0x7007, 0x0001, 0xa786, 0x0001, 0x0040, 0x1318, 0xa786, + 0x0050, 0x0040, 0x1318, 0x700c, 0xa084, 0x007f, 0x2009, 0x0040, + 0xa102, 0x8004, 0x094a, 0x20a8, 0x26a0, 0x53a6, 0x0078, 0x1169, + 0x700c, 0xa084, 0x007f, 0x0040, 0x1318, 0x80ac, 0x0048, 0x1318, + 0x2698, 0x53a5, 0x0078, 0x1169, 0x700c, 0xa084, 0x007f, 0x80ac, + 0x2698, 0x53a5, 0x0078, 0x1272, 0x1078, 0x198c, 0x00c0, 0x1284, + 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x12d0, 0x71c4, 0x70c8, + 0x2114, 0xa79e, 0x0004, 0x00c0, 0x133e, 0x200a, 0x72ca, 0x0078, + 0x1271, 0x70c7, 0x0002, 0x70cb, 0x0002, 0x70cf, 0x0000, 0x0078, + 0x1272, 0x1078, 0x198c, 0x00c0, 0x1284, 0x75d8, 0x76dc, 0x75da, + 0x76de, 0x0078, 0x1356, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, + 0x73cc, 0x74d0, 0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x0040, + 0x136e, 0x8001, 0x787a, 0x7a82, 0x7b86, 0x7d8a, 0x7e8e, 0x7c7e, + 0x78b0, 0xa084, 0xfffc, 0x78b2, 0x0078, 0x1372, 0x78b0, 0xa085, + 0x0001, 0x78b2, 0x0078, 0x1272, 0x1078, 0x198c, 0x00c0, 0x1284, + 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, 0x1381, 0x2029, 0x0000, + 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce, + 0x74d6, 0xa005, 0x0040, 0x1399, 0x8001, 0x7896, 0x7a9e, 0x7ba2, + 0x7da6, 0x7eaa, 0x7c9a, 0x78b0, 0xa084, 0xfcff, 0x78b2, 0x0078, + 0x139d, 0x78b0, 0xa085, 0x0100, 0x78b2, 0x0078, 0x1272, 0x2009, + 0x385b, 0x210c, 0x7ad4, 0x0078, 0x1270, 0x2009, 0x3841, 0x210c, + 0x0078, 0x1271, 0x2009, 0x3842, 0x210c, 0x0078, 0x1271, 0x2061, + 0x3840, 0x610c, 0x6210, 0x0078, 0x1270, 0x2009, 0x3845, 0x210c, + 0x0078, 0x1271, 0x2009, 0x3846, 0x210c, 0x0078, 0x1271, 0x2009, + 0x3847, 0x210c, 0x0078, 0x1271, 0x2009, 0x3848, 0x210c, 0x0078, + 0x1271, 0x7908, 0x7a0c, 0x0078, 0x1270, 0x71c4, 0x8107, 0xa084, + 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8, 0x3900, 0x6a00, 0x6804, + 0xa084, 0x0008, 0x0040, 0x13df, 0x6b08, 0x0078, 0x13e0, 0x6b0c, + 0x0078, 0x126f, 0x77c4, 0x1078, 0x183c, 0x2091, 0x8000, 0x6b1c, + 0x6a14, 0x2091, 0x8001, 0x2708, 0x0078, 0x126f, 0x794c, 0x0078, + 0x1271, 0x77c4, 0x1078, 0x183c, 0x2091, 0x8000, 0x6908, 0x6a18, + 0x6b10, 0x2091, 0x8001, 0x0078, 0x126f, 0x71c4, 0xa182, 0x0010, + 0x00c8, 0x126a, 0x1078, 0x1d19, 0x0078, 0x126f, 0x71c4, 0xa182, + 0x0010, 0x00c8, 0x126a, 0x2011, 0x3841, 0x2204, 0x007e, 0x2112, + 0x1078, 0x1cd2, 0x017f, 0x0078, 0x1271, 0x71c4, 0x2011, 0x1433, + 0x20a9, 0x0008, 0x2204, 0xa106, 0x0040, 0x1425, 0x8210, 0x0070, + 0x1423, 0x0078, 0x141a, 0x0078, 0x126a, 0xa292, 0x1433, 0x027e, + 0x2011, 0x3842, 0x2204, 0x2112, 0x017f, 0x007e, 0x1078, 0x1cde, + 0x017f, 0x0078, 0x1271, 0x03e8, 0x00fa, 0x01f4, 0x02ee, 0x0064, + 0x0019, 0x0032, 0x004b, 0x2061, 0x3840, 0x610c, 0x6210, 0x70c4, + 0x600e, 0x70c8, 0x6012, 0x0078, 0x1270, 0x2061, 0x3840, 0x6114, + 0x70c4, 0x6016, 0x0078, 0x1271, 0x71c4, 0x2011, 0x0004, 0x2019, + 0x1212, 0xa186, 0x0028, 0x0040, 0x1465, 0x2011, 0x0005, 0x2019, + 0x1212, 0xa186, 0x0032, 0x0040, 0x1465, 0x2011, 0x0006, 0x2019, + 0x2323, 0xa186, 0x003c, 0x00c0, 0x126a, 0x2061, 0x3840, 0x6018, + 0x007e, 0x611a, 0x23b8, 0x1078, 0x1cef, 0x1078, 0x3706, 0x017f, + 0x0078, 0x1271, 0x71c4, 0xa184, 0xffcf, 0x00c0, 0x126a, 0x2011, + 0x3847, 0x2204, 0x2112, 0x007e, 0x1078, 0x1d11, 0x017f, 0x0078, + 0x1271, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x126a, 0x2011, 0x3848, + 0x2204, 0x007e, 0x2112, 0x1078, 0x1d00, 0x017f, 0x0078, 0x1271, + 0x71c4, 0x72c8, 0xa184, 0xfffd, 0x00c0, 0x1269, 0xa284, 0xfffd, + 0x00c0, 0x1269, 0x2100, 0x7908, 0x780a, 0x2200, 0x7a0c, 0x780e, + 0x0078, 0x1270, 0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, + 0x8003, 0xa0e8, 0x3900, 0x2019, 0x0000, 0x72c8, 0x6800, 0x007e, + 0xa226, 0x0040, 0x14d1, 0x6a02, 0xa484, 0x2000, 0x0040, 0x14ba, + 0xa39d, 0x0010, 0xa484, 0x1000, 0x0040, 0x14c0, 0xa39d, 0x0008, + 0xa484, 0x4000, 0x0040, 0x14d1, 0x810f, 0xa284, 0x4000, 0x0040, + 0x14cd, 0x1078, 0x1d33, 0x0078, 0x14d1, 0x1078, 0x1d25, 0x0078, + 0x14d1, 0x72cc, 0x82ff, 0x0040, 0x14dc, 0x6808, 0xa206, 0x0040, + 0x14dc, 0x6a0a, 0xa39d, 0x000a, 0x6804, 0xa305, 0x6806, 0x027f, + 0x6b0c, 0x0078, 0x126f, 0x77c4, 0x1078, 0x183c, 0x2091, 0x8000, + 0x6a14, 0x6b1c, 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, + 0x2708, 0x0078, 0x126f, 0x70c4, 0x794c, 0x784e, 0x0078, 0x1271, + 0x71c4, 0x72c8, 0x73cc, 0xa182, 0x0010, 0x00c8, 0x126a, 0x1078, + 0x1d41, 0x0078, 0x126f, 0x77c4, 0x1078, 0x183c, 0x2091, 0x8000, + 0x6a08, 0xa295, 0x0002, 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0078, + 0x1270, 0x77c4, 0x1078, 0x183c, 0x2091, 0x8000, 0x6a08, 0xa294, + 0xfff9, 0x6a0a, 0x6804, 0xa005, 0x0040, 0x1520, 0x1078, 0x1c74, + 0x2091, 0x8001, 0x2708, 0x0078, 0x1270, 0x77c4, 0x1078, 0x183c, + 0x2091, 0x8000, 0x6a08, 0xa295, 0x0004, 0x6a0a, 0x6804, 0xa005, + 0x0040, 0x1534, 0x1078, 0x1c74, 0x2091, 0x8001, 0x2708, 0x0078, + 0x1270, 0x77c4, 0x2041, 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, + 0x1078, 0x1849, 0x2708, 0x6a08, 0x0078, 0x1270, 0x77c4, 0x73c8, + 0x72cc, 0x77c6, 0x73ca, 0x72ce, 0x1078, 0x18c4, 0x00c0, 0x1564, + 0x6818, 0xa005, 0x0040, 0x155e, 0x2708, 0x1078, 0x1d51, 0x00c0, + 0x155e, 0x7817, 0x0015, 0x2091, 0x8001, 0x007c, 0x2091, 0x8001, + 0x2001, 0x4005, 0x0078, 0x1274, 0x2091, 0x8001, 0x0078, 0x1272, + 0x77c4, 0x77c6, 0x2061, 0x3840, 0x60a3, 0x0003, 0x67b6, 0x60c7, + 0x0005, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x1078, + 0x1849, 0x7817, 0x0016, 0x1078, 0x1c74, 0x007c, 0x77c4, 0x77c6, + 0xa7bc, 0xff00, 0x2061, 0x3840, 0x60a3, 0x0002, 0x67b6, 0x60c7, + 0x0005, 0x7817, 0x0017, 0x1078, 0x1c74, 0x2041, 0x0021, 0x2049, + 0x0004, 0x2051, 0x0010, 0x1078, 0x1849, 0x8738, 0xa784, 0x0007, + 0x00c0, 0x1593, 0x007c, 0x78b0, 0xa084, 0x0003, 0x00c0, 0x15bf, + 0x2039, 0x0000, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, + 0x1078, 0x183c, 0x2091, 0x8000, 0x6808, 0xa80d, 0x690a, 0x2091, + 0x8001, 0x8738, 0xa784, 0x0007, 0x00c0, 0x15a8, 0xa7bc, 0xff00, + 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x15a8, 0x7817, + 0x0018, 0x2061, 0x3840, 0x60a3, 0x0001, 0x60c7, 0x0005, 0x1078, + 0x1c74, 0x78b0, 0xa085, 0x0002, 0x78b2, 0x007c, 0x78b0, 0xa084, + 0xfffd, 0x78b2, 0xa084, 0x0001, 0x00c0, 0x15d8, 0x1078, 0x1906, + 0x71c4, 0x71c6, 0x794a, 0x007c, 0x1078, 0x198c, 0x00c0, 0x1284, + 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x15e9, 0x2029, 0x0000, + 0x2520, 0x71c4, 0x73c8, 0x72cc, 0x71c6, 0x73ca, 0x72ce, 0x2079, + 0x3800, 0x1078, 0x1815, 0x0040, 0x1691, 0x20a9, 0x0005, 0x20a1, + 0x3816, 0x41a1, 0x2009, 0x0040, 0x1078, 0x17df, 0x0040, 0x1604, + 0x1078, 0x181e, 0x0078, 0x1691, 0x6004, 0xa084, 0xff00, 0x8007, + 0x8009, 0x0040, 0x1665, 0x0c7e, 0x2c68, 0x1078, 0x1815, 0x0040, + 0x1634, 0x2c00, 0x689e, 0x8109, 0x00c0, 0x160c, 0x609f, 0x0000, + 0x0c7f, 0x0c7e, 0x7218, 0x731c, 0x7420, 0x7524, 0x2c68, 0x689c, + 0xa065, 0x0040, 0x1664, 0x2009, 0x0040, 0x1078, 0x17df, 0x00c0, + 0x164d, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0002, 0x00c0, 0x1634, + 0x2d00, 0x6002, 0x0078, 0x161a, 0x0c7f, 0x0c7e, 0x609c, 0x2060, + 0x1078, 0x187e, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1695, 0x2009, + 0x001c, 0x6008, 0xa085, 0x0200, 0x600a, 0x6004, 0x6086, 0x1078, + 0x17a5, 0x1078, 0x181e, 0x0078, 0x1691, 0x0c7f, 0x0c7e, 0x609c, + 0x2060, 0x1078, 0x187e, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1695, + 0x2009, 0x001c, 0x6087, 0x0103, 0x601b, 0x0003, 0x1078, 0x17a5, + 0x1078, 0x181e, 0x0078, 0x1691, 0x0c7f, 0x74c4, 0x73c8, 0x72cc, + 0x6014, 0x7817, 0x0012, 0x0e7e, 0x2071, 0x3840, 0x70a3, 0x0005, + 0x70a7, 0x0000, 0x73aa, 0x72ae, 0x74b2, 0x70b6, 0x70bb, 0x0000, + 0x2c00, 0x70be, 0x70c3, 0x0000, 0xa02e, 0x2530, 0x611c, 0xa184, + 0x0060, 0x0040, 0x1685, 0x1078, 0x320a, 0x0e7f, 0x6596, 0x65a6, + 0x669a, 0x669a, 0x60af, 0x0000, 0x60b3, 0x0000, 0x1078, 0x1c74, + 0x007c, 0x70c3, 0x4005, 0x0078, 0x1275, 0x20a9, 0x0005, 0x2099, + 0x3816, 0x530a, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, + 0xa5a9, 0x0000, 0x007c, 0x71c4, 0x70c7, 0x0000, 0x7906, 0x0078, + 0x1272, 0x71c4, 0x71c6, 0x2168, 0x0078, 0x16b0, 0x2069, 0x1000, + 0x690c, 0xa016, 0x2d04, 0xa210, 0x8d68, 0x8109, 0x00c0, 0x16b2, + 0xa285, 0x0000, 0x00c0, 0x16c0, 0x70c3, 0x4000, 0x0078, 0x16c2, + 0x70c3, 0x4003, 0x70ca, 0x0078, 0x1275, 0x79c8, 0x0078, 0x1271, + 0x71c4, 0x71c6, 0x2198, 0x20a1, 0x0042, 0x20a9, 0x0004, 0x53a3, + 0x21a0, 0x2099, 0x0042, 0x20a9, 0x0004, 0x53a3, 0x0078, 0x1272, + 0x70c4, 0x2068, 0x2079, 0x3800, 0x1078, 0x1815, 0x0040, 0x1750, + 0x6007, 0x0001, 0x600b, 0x0000, 0x602b, 0x0000, 0x601b, 0x0006, + 0x6a10, 0xa28c, 0x0007, 0xa284, 0x00f0, 0x8003, 0x8003, 0x8003, + 0x8003, 0xa105, 0x6016, 0xa284, 0x0800, 0x0040, 0x16fb, 0x601b, + 0x000a, 0x0078, 0x1701, 0xa284, 0x1000, 0x0040, 0x1701, 0x601b, + 0x000c, 0xa284, 0x0300, 0x0040, 0x170a, 0x602b, 0x0001, 0x8004, + 0x8004, 0x8004, 0xa085, 0x0001, 0x601e, 0x6023, 0x0000, 0x6027, + 0x000a, 0xa284, 0x0400, 0x0040, 0x1717, 0x602b, 0x0000, 0x20a9, + 0x0006, 0xac80, 0x000b, 0x20a0, 0xad80, 0x0005, 0x2098, 0x53a3, + 0xa284, 0x0300, 0x00c0, 0x172c, 0x6046, 0x604a, 0x604e, 0x6052, + 0x6096, 0x609a, 0x0078, 0x1736, 0x6800, 0x6046, 0x6804, 0x604a, + 0x6e08, 0x664e, 0x6d0c, 0x6552, 0x6596, 0x669a, 0x6014, 0x7817, + 0x0042, 0x2c08, 0x2061, 0x3840, 0x60a3, 0x0005, 0x60a7, 0x0000, + 0x60ab, 0x0000, 0x60af, 0x0000, 0x60b3, 0x0000, 0x60b6, 0x61be, + 0xa284, 0x0400, 0x60c2, 0x1078, 0x31f5, 0x1078, 0x1c74, 0x007c, + 0x70c3, 0x4005, 0x0078, 0x1275, 0x78e0, 0xa005, 0x0040, 0x1280, + 0x2091, 0x8000, 0x70c4, 0x800a, 0x2011, 0x0010, 0x810c, 0x0048, + 0x1766, 0x3a00, 0xa084, 0xfff7, 0x0078, 0x1769, 0x3a00, 0xa085, + 0x0008, 0x20d0, 0x0005, 0x0005, 0xa084, 0xfffb, 0x20d0, 0x0005, + 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0xa085, + 0x0004, 0x20d0, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, + 0x0005, 0x0005, 0x8211, 0x00c0, 0x175e, 0x3a00, 0xa085, 0x0008, + 0x20d0, 0x2091, 0x8001, 0x0078, 0x1272, 0x2011, 0x04fd, 0x2204, + 0xa082, 0x0004, 0x0048, 0x17a1, 0x78e3, 0x0001, 0x2009, 0xff01, + 0x200a, 0x2001, 0x000c, 0x20d8, 0x2001, 0x000c, 0x20d0, 0x0078, + 0x1272, 0x2001, 0x4005, 0x0078, 0x1274, 0x700c, 0xa084, 0x00ff, + 0x0040, 0x17b1, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, + 0x17ac, 0x7017, 0x0000, 0x7112, 0x721a, 0x731e, 0x7422, 0x7526, + 0xac80, 0x0001, 0x8108, 0x810c, 0x81a9, 0x8098, 0x20a1, 0x0030, + 0x6084, 0x20a2, 0x53a6, 0x780c, 0xa085, 0x0000, 0x7002, 0x7007, + 0x0001, 0x2009, 0x0022, 0x2104, 0xa084, 0x4000, 0x00c0, 0x17c9, + 0x7108, 0x8103, 0x00c8, 0x17c9, 0x7014, 0xa005, 0x0040, 0x17c9, + 0x7007, 0x0002, 0xa184, 0x0060, 0x7003, 0x0000, 0x007c, 0x700c, + 0xa084, 0x00ff, 0x0040, 0x17eb, 0x7007, 0x0004, 0x7004, 0xa084, + 0x0004, 0x00c0, 0x17e6, 0x7017, 0x0000, 0x7112, 0x721a, 0x7422, + 0x7526, 0x731e, 0x2099, 0x0030, 0x8108, 0x81ac, 0x780c, 0xa085, + 0x0001, 0x7002, 0x7007, 0x0001, 0x2009, 0x0022, 0x2104, 0xa084, + 0x4000, 0x00c0, 0x17fc, 0x7008, 0x800b, 0x00c8, 0x17fc, 0x7007, + 0x0002, 0xa08c, 0x0060, 0x00c0, 0x1812, 0xac80, 0x0001, 0x20a0, + 0x53a5, 0xa006, 0x7003, 0x0000, 0x007c, 0x7850, 0xa065, 0x0040, + 0x181d, 0x2c04, 0x7852, 0x2063, 0x0000, 0x007c, 0x0f7e, 0x2079, + 0x3800, 0x7850, 0x2062, 0x2c00, 0xa005, 0x00c0, 0x1829, 0x1078, + 0x1e2a, 0x7852, 0x0f7f, 0x007c, 0x2011, 0x4300, 0x7a52, 0x7bd4, + 0x8319, 0x0040, 0x1839, 0xa280, 0x002f, 0x2012, 0x2010, 0x0078, + 0x1830, 0x2013, 0x0000, 0x007c, 0xa784, 0x0f00, 0x800c, 0xa784, + 0x0007, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa0e8, 0x3980, + 0x007c, 0x1078, 0x183c, 0x2900, 0x682a, 0x2a00, 0x682e, 0x6808, + 0xa084, 0xffef, 0xa80d, 0x690a, 0x2091, 0x8000, 0x2009, 0x384f, + 0x210c, 0x6804, 0xa005, 0x0040, 0x1866, 0xa116, 0x00c0, 0x1866, + 0x2060, 0x6000, 0x6806, 0x017e, 0x0078, 0x1869, 0x2009, 0x0000, + 0x017e, 0x6804, 0xa065, 0x0040, 0x1878, 0x6000, 0x6806, 0x1078, + 0x188b, 0x1078, 0x1992, 0x6810, 0x8001, 0x6812, 0x00c0, 0x1869, + 0x017f, 0x6902, 0x6906, 0x2091, 0x8001, 0x007c, 0xa065, 0x0040, + 0x188a, 0x609c, 0x609f, 0x0000, 0x2008, 0x1078, 0x181e, 0x2100, + 0x0078, 0x187e, 0x007c, 0x6007, 0x0103, 0x20a9, 0x001c, 0xac80, + 0x0005, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828, 0x601a, 0x682c, + 0x6022, 0x007c, 0x0e7e, 0x2071, 0x3840, 0x7040, 0xa08c, 0x0080, + 0x00c0, 0x18a8, 0xa088, 0x3880, 0x2d0a, 0x8000, 0x7042, 0xa006, + 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0x3840, 0x2009, 0x3880, 0x7240, + 0x8221, 0x8211, 0x0048, 0x18c2, 0x2104, 0x8108, 0xad06, 0x00c0, + 0x18b1, 0x8119, 0x211e, 0x8108, 0x8318, 0x8211, 0x00c8, 0x18ba, + 0x7442, 0xa006, 0x0e7f, 0x007c, 0x1078, 0x183c, 0x2091, 0x8000, + 0x6804, 0x781e, 0xa065, 0x0040, 0x1905, 0x0078, 0x18d5, 0x2c00, + 0x781e, 0x6000, 0xa065, 0x0040, 0x1905, 0x6010, 0xa306, 0x00c0, + 0x18cf, 0x600c, 0xa206, 0x00c0, 0x18cf, 0x2c28, 0x6804, 0xac06, + 0x00c0, 0x18ec, 0x6000, 0x2060, 0x6806, 0xa005, 0x00c0, 0x18ec, + 0x6803, 0x0000, 0x0078, 0x18f6, 0x6400, 0x781c, 0x2060, 0x6402, + 0xa486, 0x0000, 0x00c0, 0x18f6, 0x2c00, 0x6802, 0x2560, 0x1078, + 0x188b, 0x601b, 0x0005, 0x6023, 0x0020, 0x1078, 0x1992, 0x6810, + 0x8001, 0x6812, 0x2001, 0xffff, 0xa005, 0x007c, 0x2039, 0x0000, + 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x1078, 0x1849, + 0x8738, 0xa784, 0x0007, 0x00c0, 0x190e, 0xa7bc, 0xff00, 0x873f, + 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x190e, 0x007c, 0x2061, + 0x0000, 0x6018, 0xa084, 0x0001, 0x00c0, 0x1930, 0x2091, 0x8000, + 0x78c4, 0x78c7, 0x0000, 0x2091, 0x8001, 0xa005, 0x00c0, 0x1931, + 0x007c, 0xa08c, 0xfff0, 0x0040, 0x1937, 0x1078, 0x1e2a, 0x0079, + 0x1939, 0x1949, 0x194b, 0x1951, 0x1955, 0x1949, 0x1959, 0x1949, + 0x1960, 0x1964, 0x1968, 0x1949, 0x1949, 0x1949, 0x1949, 0x1949, + 0x1949, 0x1078, 0x1e2a, 0x1078, 0x1906, 0x2001, 0x8001, 0x0078, + 0x1274, 0x2001, 0x8003, 0x0078, 0x1274, 0x2001, 0x8004, 0x0078, + 0x1274, 0x1078, 0x1906, 0x2001, 0x8006, 0x007c, 0x0078, 0x1274, + 0x2001, 0x8008, 0x0078, 0x1274, 0x2001, 0x8009, 0x0078, 0x1274, + 0x2091, 0x8000, 0x2069, 0x3840, 0x6800, 0xa086, 0x0000, 0x0040, + 0x1976, 0x2091, 0x8001, 0x78c7, 0x0009, 0x007c, 0x68b4, 0xa0bc, + 0xff00, 0x2091, 0x8000, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, + 0x0010, 0x1078, 0x1849, 0x8738, 0xa784, 0x0007, 0x00c0, 0x1981, + 0x2001, 0x800a, 0x0078, 0x1274, 0x2001, 0x04fd, 0x2004, 0xa086, + 0x0004, 0x007c, 0x6004, 0x6086, 0x2c08, 0x2063, 0x0000, 0x786c, + 0x8000, 0x786e, 0x7870, 0xa005, 0x7972, 0x0040, 0x19a2, 0x2c02, + 0x0078, 0x19a3, 0x7976, 0x007c, 0x0c7e, 0x2061, 0x3800, 0x6887, + 0x0103, 0x2d08, 0x206b, 0x0000, 0x606c, 0x8000, 0x606e, 0x6070, + 0xa005, 0x6172, 0x0040, 0x19b7, 0x2d02, 0x0078, 0x19b8, 0x6176, + 0x0c7f, 0x007c, 0x1078, 0x19cb, 0x0040, 0x19ca, 0x0c7e, 0x609c, + 0xa065, 0x0040, 0x19c5, 0x1078, 0x187e, 0x0c7f, 0x609f, 0x0000, + 0x1078, 0x181e, 0x007c, 0x7874, 0xa065, 0x0040, 0x19dd, 0x2091, + 0x8000, 0x786c, 0x8001, 0x786e, 0x2c04, 0x7876, 0xa005, 0x00c0, + 0x19db, 0x7872, 0x8000, 0x2091, 0x8001, 0x007c, 0x20a9, 0x0010, + 0xa006, 0x8004, 0x8086, 0x818e, 0x00c8, 0x19e7, 0xa200, 0x0070, + 0x19eb, 0x0078, 0x19e2, 0x8086, 0x818e, 0x007c, 0x157e, 0x20a9, + 0x0010, 0xa005, 0x0040, 0x1a11, 0xa11a, 0x00c8, 0x1a11, 0x8213, + 0x818d, 0x0048, 0x1a02, 0xa11a, 0x00c8, 0x1a03, 0x0070, 0x1a09, + 0x0078, 0x19f7, 0xa11a, 0x2308, 0x8210, 0x0070, 0x1a09, 0x0078, + 0x19f7, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f, + 0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x1a0d, 0x797c, + 0x70d0, 0x007e, 0x007f, 0xa106, 0x0040, 0x1a67, 0x2091, 0x8000, + 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x1a67, 0x7008, 0x7208, + 0xa206, 0x00c0, 0x1a67, 0xa286, 0x0008, 0x00c0, 0x1a67, 0x2071, + 0x0010, 0x1078, 0x1815, 0x0040, 0x1a67, 0x7a84, 0x7b80, 0x7c8c, + 0x7d88, 0x8107, 0x8004, 0x8004, 0xa210, 0xa399, 0x0000, 0x2009, + 0x0040, 0x1078, 0x17df, 0x2091, 0x8001, 0x0040, 0x1a5e, 0x1078, + 0x181e, 0x7890, 0x8000, 0x7892, 0xa086, 0x0002, 0x00c0, 0x1a67, + 0x2091, 0x8000, 0x78c7, 0x0002, 0x7893, 0x0000, 0x78b0, 0xa085, + 0x0003, 0x78b2, 0x2091, 0x8001, 0x0078, 0x1a67, 0x7893, 0x0000, + 0x1078, 0x1bb6, 0x6004, 0xa084, 0x000f, 0x0079, 0x1a6c, 0x2071, + 0x0010, 0x2091, 0x8001, 0x007c, 0x1a7c, 0x1a9e, 0x1ac4, 0x1a7c, + 0x1ad6, 0x1a8b, 0x1a7c, 0x1a7c, 0x1a7c, 0x1a98, 0x1abe, 0x1a7c, + 0x1a7c, 0x1a7c, 0x1a7c, 0x1a7c, 0x2039, 0x0400, 0x78c0, 0xa705, + 0x78c2, 0x6008, 0xa705, 0x600a, 0x1078, 0x1b14, 0x609c, 0x78be, + 0x1078, 0x1b9e, 0x007c, 0x78c0, 0xa084, 0x0100, 0x0040, 0x1a92, + 0x0078, 0x1a7c, 0x601c, 0xa085, 0x0080, 0x601e, 0x0078, 0x1aa5, + 0x1078, 0x198c, 0x00c0, 0x1a7c, 0x1078, 0x1bd0, 0x78c0, 0xa084, + 0x0100, 0x0040, 0x1aa5, 0x0078, 0x1a7c, 0x78c3, 0x0000, 0x6004, + 0x8007, 0xa084, 0x00ff, 0x78b6, 0x8001, 0x609f, 0x0000, 0x0040, + 0x1abb, 0x1078, 0x1b14, 0x0040, 0x1abb, 0x78c0, 0xa085, 0x0100, + 0x78c2, 0x0078, 0x1abd, 0x1078, 0x1b38, 0x007c, 0x1078, 0x198c, + 0x00c0, 0x1a7c, 0x1078, 0x1bcc, 0x78c0, 0xa08c, 0x0e00, 0x00c0, + 0x1acd, 0xa084, 0x0100, 0x00c0, 0x1acf, 0x0078, 0x1a7c, 0x1078, + 0x1b14, 0x00c0, 0x1ad5, 0x1078, 0x1b38, 0x007c, 0x78c0, 0xa084, + 0x0100, 0x0040, 0x1add, 0x0078, 0x1a7c, 0x78c3, 0x0000, 0x6714, + 0x20a9, 0x0001, 0x6018, 0xa005, 0x0040, 0x1af8, 0xa7bc, 0xff00, + 0x20a9, 0x0008, 0xa08e, 0x0001, 0x0040, 0x1af8, 0x2039, 0x0000, + 0x20a9, 0x0080, 0xa08e, 0x0002, 0x0040, 0x1af8, 0x0078, 0x1b11, + 0x1078, 0x183c, 0x2d00, 0xa088, 0x0002, 0x2091, 0x8000, 0x2168, + 0x682b, 0x0000, 0x682f, 0x0000, 0x2104, 0xa084, 0xffde, 0x200a, + 0x2100, 0xa088, 0x0010, 0x2091, 0x8001, 0x0070, 0x1b11, 0x0078, + 0x1afd, 0x1078, 0x181e, 0x007c, 0x78b8, 0xa06d, 0x00c0, 0x1b1f, + 0x2c00, 0x78ba, 0x78be, 0x609f, 0x0000, 0x0078, 0x1b2b, 0x2c00, + 0x689e, 0x609f, 0x0000, 0x78ba, 0x2d00, 0x6002, 0x78bc, 0xad06, + 0x00c0, 0x1b2b, 0x6002, 0x78b4, 0x8001, 0x78b6, 0x00c0, 0x1b37, + 0x78c0, 0xa084, 0x0000, 0x78c2, 0x78bc, 0x2060, 0xa006, 0x007c, + 0xa02e, 0x2530, 0x611c, 0x61a2, 0xa184, 0xc1ff, 0x601e, 0xa184, + 0x0060, 0x0040, 0x1b47, 0x0e7e, 0x1078, 0x320a, 0x0e7f, 0x6596, + 0x669a, 0x6714, 0x1078, 0x183c, 0x2091, 0x8000, 0x6808, 0xa084, + 0x0001, 0x0040, 0x1b63, 0x2091, 0x8001, 0x1078, 0x188b, 0x2091, + 0x8000, 0x1078, 0x1992, 0x2091, 0x8001, 0x78bb, 0x0000, 0x78bf, + 0x0000, 0x0078, 0x1b9d, 0x6024, 0xa096, 0x0001, 0x00c0, 0x1b6a, + 0x8000, 0x6026, 0x6a10, 0x6814, 0x2091, 0x8001, 0xa202, 0x0048, + 0x1b79, 0x0040, 0x1b79, 0x2039, 0x0200, 0x1078, 0x1b9e, 0x0078, + 0x1b9d, 0x2c08, 0x2091, 0x8000, 0x6800, 0xa065, 0x0040, 0x1b81, + 0x6102, 0x6902, 0x00c0, 0x1b85, 0x6906, 0x2160, 0x6003, 0x0000, + 0x6810, 0x8000, 0x6812, 0x2091, 0x8001, 0x6808, 0xa08c, 0x0040, + 0x0040, 0x1b97, 0xa086, 0x0040, 0x680a, 0x1078, 0x189a, 0x1078, + 0x1c74, 0x78bf, 0x0000, 0x78bb, 0x0000, 0x007c, 0x6008, 0xa705, + 0x600a, 0x2091, 0x8000, 0x1078, 0x1992, 0x2091, 0x8001, 0x78bc, + 0xa065, 0x0040, 0x1bb1, 0x609c, 0x78be, 0x609f, 0x0000, 0x0078, + 0x1ba1, 0x78bb, 0x0000, 0x78bf, 0x0000, 0x007c, 0x7978, 0x787c, + 0x8000, 0xa10a, 0x00c8, 0x1bbd, 0xa006, 0x787e, 0x70d2, 0x7804, + 0xa005, 0x0040, 0x1bcb, 0x8001, 0x7806, 0x00c0, 0x1bcb, 0x0068, + 0x1bcb, 0x2091, 0x4080, 0x007c, 0x2039, 0x1be4, 0x0078, 0x1bd2, + 0x2039, 0x1bea, 0x2704, 0xa005, 0x0040, 0x1be3, 0xac00, 0x2068, + 0x6b08, 0x6c0c, 0x6910, 0x6a14, 0x690a, 0x6a0e, 0x6b12, 0x6c16, + 0x8738, 0x0078, 0x1bd2, 0x007c, 0x0003, 0x0009, 0x000f, 0x0015, + 0x001b, 0x0000, 0x0015, 0x001b, 0x0000, 0x0068, 0x1c05, 0x2029, + 0x0000, 0x7874, 0xa065, 0x0040, 0x1c00, 0x1078, 0x1c06, 0x0040, + 0x1c00, 0x1078, 0x1c17, 0x00c0, 0x1c00, 0x8528, 0x0078, 0x1bf1, + 0x85ff, 0x0040, 0x1c05, 0x2091, 0x4080, 0x007c, 0x7b94, 0x7998, + 0x70d4, 0x007e, 0x007f, 0xa102, 0x00c0, 0x1c11, 0x2300, 0xa005, + 0x007c, 0x0048, 0x1c15, 0xa302, 0x007c, 0x8002, 0x007c, 0x2091, + 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x1c5b, 0x7008, + 0x7208, 0xa206, 0x00c0, 0x1c5b, 0xa286, 0x0008, 0x00c0, 0x1c5b, + 0x2071, 0x0010, 0x1078, 0x1c60, 0x2009, 0x001c, 0x6028, 0xa005, + 0x0040, 0x1c34, 0x2009, 0x0040, 0x1078, 0x17a5, 0x0040, 0x1c4d, + 0x78ac, 0x8000, 0x78ae, 0xa086, 0x0002, 0x00c0, 0x1c5b, 0x2091, + 0x8000, 0x78c7, 0x0003, 0x78af, 0x0000, 0x78b0, 0xa085, 0x0300, + 0x78b2, 0x2091, 0x8001, 0x0078, 0x1c5b, 0x78af, 0x0000, 0x1078, + 0x19ba, 0x7994, 0x7898, 0x8000, 0xa10a, 0x00c8, 0x1c58, 0xa006, + 0x789a, 0x70d6, 0xa006, 0x2071, 0x0010, 0x2091, 0x8001, 0x007c, + 0x8107, 0x8004, 0x8004, 0x7aa0, 0x7b9c, 0x7ca8, 0x7da4, 0xa210, + 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x007c, 0x2009, + 0x3868, 0x2091, 0x8000, 0x200a, 0x0f7e, 0x2079, 0x0100, 0x2009, + 0x3840, 0x2091, 0x8000, 0x2104, 0xa086, 0x0000, 0x00c0, 0x1c8f, + 0x2009, 0x3812, 0x2104, 0xa005, 0x00c0, 0x1c8f, 0x7830, 0xa084, + 0x00c0, 0x00c0, 0x1c8f, 0x0018, 0x1c8f, 0x781b, 0x0045, 0x2091, + 0x8001, 0x0f7f, 0x007c, 0x127e, 0x2091, 0x2300, 0x2071, 0x3840, + 0x2079, 0x0100, 0x784b, 0x000f, 0x2019, 0x3105, 0x20a1, 0x012b, + 0x2304, 0xa005, 0x0040, 0x1cad, 0x789a, 0x8318, 0x23ac, 0x8318, + 0x2398, 0x53a6, 0x3318, 0x0078, 0x1ca0, 0x789b, 0x0020, 0x20a9, + 0x0010, 0x78af, 0x0000, 0x78af, 0x0020, 0x0070, 0x1cb9, 0x0078, + 0x1cb1, 0x7003, 0x0000, 0x1078, 0x1dbe, 0x7004, 0xa084, 0x000f, + 0xa085, 0x6280, 0x7806, 0x780f, 0x9200, 0x7843, 0x00d8, 0x7853, + 0x0080, 0x780b, 0x0008, 0x7047, 0x387f, 0x7043, 0x0000, 0x127f, + 0x2000, 0x007c, 0xa18c, 0x000f, 0x2011, 0x0101, 0x2204, 0xa084, + 0xfff0, 0xa105, 0x2012, 0x1078, 0x1dbe, 0x007c, 0x2011, 0x0101, + 0x20a9, 0x0009, 0x810b, 0x0070, 0x1ce7, 0x0078, 0x1ce2, 0xa18c, + 0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, 0x007c, 0x2009, + 0x0101, 0x20a9, 0x0005, 0x8213, 0x0070, 0x1cf8, 0x0078, 0x1cf3, + 0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f, 0xa205, 0x200a, 0x007c, + 0x2011, 0x0101, 0x20a9, 0x000c, 0x810b, 0x0070, 0x1d09, 0x0078, + 0x1d04, 0xa18c, 0xf000, 0x2204, 0xa084, 0x0fff, 0xa105, 0x2012, + 0x007c, 0x2011, 0x0102, 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012, + 0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100, + 0x609a, 0x62ac, 0x63ac, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, + 0x0022, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0xa084, 0xffdf, + 0x60ae, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0022, 0x0c7e, + 0x2061, 0x0100, 0x609a, 0x60a4, 0xa085, 0x0020, 0x60ae, 0x0c7f, + 0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100, + 0x609a, 0x60a4, 0x62ae, 0x2010, 0x60a4, 0x63ae, 0x2018, 0x0c7f, + 0x007c, 0x0c7e, 0x0e7e, 0x6818, 0xa005, 0x0040, 0x1d9a, 0x2061, + 0x4280, 0x1078, 0x1da0, 0x0040, 0x1d84, 0x20a9, 0x0000, 0x2061, + 0x4180, 0x0c7e, 0x1078, 0x1da0, 0x0040, 0x1d6e, 0x0c7f, 0x8c60, + 0x0070, 0x1d6c, 0x0078, 0x1d61, 0x0078, 0x1d9a, 0x007f, 0xa082, + 0x4180, 0x2071, 0x3840, 0x70ba, 0x6020, 0xa085, 0x0800, 0x6022, + 0x2091, 0x8001, 0x71b6, 0x2001, 0x0004, 0x70a2, 0x70c7, 0x0005, + 0x1078, 0x1c6f, 0x0078, 0x1d96, 0x2071, 0x3840, 0x6020, 0xa085, + 0x0800, 0x6022, 0x2091, 0x8001, 0x71b6, 0x2c00, 0x70be, 0x2001, + 0x0006, 0x70a2, 0x70c7, 0x0005, 0x1078, 0x1c6f, 0x2001, 0x0000, + 0x0078, 0x1d9c, 0x2001, 0x0001, 0xa005, 0x0e7f, 0x0c7f, 0x007c, + 0x2091, 0x8000, 0x2c04, 0xa005, 0x0040, 0x1db9, 0x2060, 0x6010, + 0xa306, 0x00c0, 0x1db6, 0x600c, 0xa206, 0x00c0, 0x1db6, 0x6014, + 0xa106, 0x00c0, 0x1db6, 0xa006, 0x0078, 0x1dbd, 0x6000, 0x0078, + 0x1da3, 0xa085, 0x0001, 0x2091, 0x8001, 0x007c, 0x2011, 0x3841, + 0x220c, 0xa18c, 0x000f, 0x2011, 0x013b, 0x2204, 0xa084, 0x0100, + 0x0040, 0x1dd4, 0x2021, 0xff04, 0x2122, 0x810b, 0x810b, 0x810b, + 0x810b, 0xa18d, 0x0f00, 0x2104, 0x007c, 0x0e7e, 0x68e4, 0xa08c, + 0x0020, 0x0040, 0x1e28, 0xa084, 0x0006, 0x00c0, 0x1e28, 0x6014, + 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0f0, 0x3900, + 0x7004, 0xa084, 0x000a, 0x00c0, 0x1e28, 0x7108, 0xa194, 0xff00, + 0x0040, 0x1e28, 0xa18c, 0x00ff, 0x2001, 0x000c, 0xa106, 0x0040, + 0x1e0f, 0x2001, 0x0012, 0xa106, 0x0040, 0x1e13, 0x2001, 0x0014, + 0xa106, 0x0040, 0x1e17, 0x2001, 0x0019, 0xa106, 0x0040, 0x1e1b, + 0x2001, 0x0032, 0xa106, 0x0040, 0x1e1f, 0x0078, 0x1e23, 0x2009, + 0x0012, 0x0078, 0x1e25, 0x2009, 0x0014, 0x0078, 0x1e25, 0x2009, + 0x0019, 0x0078, 0x1e25, 0x2009, 0x0020, 0x0078, 0x1e25, 0x2009, + 0x003f, 0x0078, 0x1e25, 0x2011, 0x0000, 0x2100, 0xa205, 0x700a, + 0x0e7f, 0x007c, 0x2071, 0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3, + 0x8002, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, + 0x1e37, 0x107e, 0x007e, 0x127e, 0x2091, 0x2300, 0x7f3c, 0x7e58, + 0x7c30, 0x7d38, 0x2009, 0x3874, 0x78a0, 0x200a, 0x8108, 0x250a, + 0x8108, 0x240a, 0x8108, 0x260a, 0x8108, 0x270a, 0xa594, 0x003f, + 0xa484, 0x4000, 0x0040, 0x1e5a, 0xa784, 0x007c, 0x00c0, 0x308f, + 0x1078, 0x1e2a, 0xa49c, 0x000f, 0xa382, 0x0004, 0x0050, 0x1e62, + 0x1078, 0x1e2a, 0x8507, 0xa084, 0x000f, 0x0079, 0x1e67, 0x22d0, + 0x236f, 0x238c, 0x25f7, 0x283b, 0x287e, 0x28c7, 0x2925, 0x29bc, + 0x2a49, 0x1e8f, 0x1e77, 0x2139, 0x21fe, 0x281a, 0x1e77, 0x1078, + 0x1e2a, 0x0018, 0x1e3e, 0x127f, 0x2091, 0x8001, 0x007f, 0x107f, + 0x007c, 0x7003, 0x0000, 0x703f, 0x0000, 0x7030, 0xa005, 0x0040, + 0x1e8b, 0x7033, 0x0000, 0x1078, 0x306a, 0x0018, 0x1e3e, 0x2009, + 0x380f, 0x200b, 0x0000, 0x705c, 0xa005, 0x00c0, 0x1f58, 0x70a0, + 0xa084, 0x0007, 0x0079, 0x1e9c, 0x1f7b, 0x1ea4, 0x1eb2, 0x1ecd, + 0x1eed, 0x1f36, 0x1f11, 0x1ea4, 0x7808, 0xa084, 0xfffd, 0x780a, + 0x2009, 0x0047, 0x1078, 0x271f, 0x00c0, 0x1eb0, 0x7003, 0x0004, + 0x0078, 0x1e79, 0x1078, 0x3051, 0x00c0, 0x1ecb, 0x70b4, 0x8007, + 0x7882, 0x789b, 0x0010, 0x78ab, 0x000c, 0x789b, 0x0060, 0x78ab, + 0x0001, 0x785b, 0x0004, 0x2009, 0x00fb, 0x1078, 0x271d, 0x00c0, + 0x1ecb, 0x7003, 0x0004, 0x0078, 0x1e79, 0x1078, 0x3051, 0x00c0, + 0x1eeb, 0x71b4, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x0007, + 0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, + 0x0002, 0x785b, 0x0004, 0x2009, 0x00fb, 0x1078, 0x271d, 0x00c0, + 0x1eeb, 0x7003, 0x0004, 0x0078, 0x1e79, 0x1078, 0x3051, 0x00c0, + 0x1f0f, 0x71b4, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x0007, + 0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0020, 0x71b8, 0x79aa, 0x78ab, + 0x000d, 0x789b, 0x0060, 0x78ab, 0x0004, 0x785b, 0x0004, 0x2009, + 0x00fb, 0x1078, 0x271d, 0x00c0, 0x1f0f, 0x7003, 0x0004, 0x0078, + 0x1e79, 0x1078, 0x3051, 0x00c0, 0x1f34, 0x71b4, 0x8107, 0x7882, + 0x789b, 0x0010, 0xa18c, 0x0007, 0xa18d, 0x00c0, 0x79aa, 0x78ab, + 0x0006, 0x789b, 0x0060, 0x78ab, 0x0002, 0x785b, 0x0004, 0x2009, + 0x00fb, 0x1078, 0x271d, 0x00c0, 0x1f34, 0x70bc, 0x70bf, 0x0000, + 0x2068, 0x703e, 0x7003, 0x0002, 0x0078, 0x1e79, 0x1078, 0x3051, + 0x00c0, 0x1e79, 0x70bc, 0x2068, 0x1078, 0x30f3, 0x789b, 0x0010, + 0x6814, 0xa084, 0x0007, 0xa085, 0x0080, 0x007e, 0x007f, 0x78aa, + 0x6e1c, 0x067e, 0x067f, 0x2041, 0x0001, 0x70c0, 0xa084, 0x0400, + 0x2001, 0x0004, 0x0040, 0x1f56, 0x2001, 0x0006, 0x0078, 0x2057, + 0x1078, 0x3051, 0x00c0, 0x1e79, 0x789b, 0x0010, 0x705c, 0x2068, + 0x1078, 0x30f3, 0x6f14, 0x1078, 0x2f99, 0x6008, 0xa085, 0x0010, + 0x600a, 0xad80, 0x0009, 0x2003, 0x0005, 0x6814, 0xa084, 0x0007, + 0xa085, 0x0080, 0x78aa, 0x2031, 0x0020, 0x2041, 0x0001, 0x2001, + 0x0003, 0x0078, 0x2057, 0x0018, 0x1e3e, 0x7440, 0xa485, 0x0000, + 0x0040, 0x1f95, 0xa080, 0x3880, 0x2030, 0x7144, 0x8108, 0xa12a, + 0x0048, 0x1f8c, 0x2009, 0x3880, 0x2164, 0x6504, 0x85ff, 0x00c0, + 0x1fa2, 0x8421, 0x00c0, 0x1f86, 0x7146, 0x7003, 0x0000, 0x703f, + 0x0000, 0x0078, 0x1e79, 0x7640, 0xa6b0, 0x3880, 0x7144, 0x2600, + 0x0078, 0x1f91, 0x7146, 0x2568, 0x2558, 0x753e, 0x2c50, 0x6708, + 0x7736, 0xa784, 0x013f, 0x0040, 0x1fcf, 0xa784, 0x0021, 0x00c0, + 0x1f9f, 0xa784, 0x0002, 0x0040, 0x1fbc, 0xa784, 0x0004, 0x0040, + 0x1f9f, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0008, 0x00c0, 0x1f9f, + 0xa784, 0x0010, 0x00c0, 0x1f9f, 0xa784, 0x0100, 0x0040, 0x1fcf, + 0x6018, 0xa005, 0x00c0, 0x1f9f, 0xa7bc, 0xfeff, 0x670a, 0x6823, + 0x0000, 0x6e1c, 0xa684, 0x000e, 0x6118, 0x0040, 0x1fdf, 0x601c, + 0xa102, 0x0048, 0x1fe2, 0x0040, 0x1fe2, 0x0078, 0x1f9b, 0x81ff, + 0x00c0, 0x1f9b, 0xa784, 0x0080, 0x00c0, 0x1fe8, 0x700c, 0x6022, + 0x1078, 0x30f3, 0x0018, 0x1e3e, 0x789b, 0x0010, 0xa046, 0x1078, + 0x3051, 0x00c0, 0x1e79, 0x6b14, 0xa39c, 0x0007, 0xa39d, 0x00c0, + 0x704c, 0xa084, 0x8000, 0x0040, 0x2001, 0xa684, 0x0001, 0x0040, + 0x2003, 0xa39c, 0xffbf, 0xa684, 0x0010, 0x0040, 0x2009, 0xa39d, + 0x0020, 0x7baa, 0x8840, 0xa684, 0x000e, 0x00c0, 0x2014, 0xa7bd, + 0x0010, 0x670a, 0x0078, 0x2055, 0x714c, 0xa18c, 0x0800, 0x0040, + 0x2c2b, 0x2011, 0x0021, 0x8004, 0x8004, 0x0048, 0x202b, 0x2011, + 0x0022, 0x8004, 0x0048, 0x202b, 0x2011, 0x0020, 0x8004, 0x0048, + 0x202b, 0x0040, 0x2055, 0x7aaa, 0x8840, 0x1078, 0x306a, 0x6a14, + 0x610c, 0x8108, 0xa18c, 0x00ff, 0xa1e0, 0x4180, 0x2c64, 0x8cff, + 0x0040, 0x204c, 0x6014, 0xa206, 0x00c0, 0x2036, 0x60b8, 0x8001, + 0x60ba, 0x00c0, 0x2031, 0x0c7e, 0x2a60, 0x6008, 0xa085, 0x0100, + 0x600a, 0x0c7f, 0x0078, 0x1f7b, 0x1078, 0x3051, 0x00c0, 0x1e79, + 0x2a60, 0x610e, 0x79aa, 0x8840, 0x712e, 0x2001, 0x0001, 0x007e, + 0x7150, 0xa184, 0x0018, 0x0040, 0x2072, 0xa184, 0x0010, 0x0040, + 0x2065, 0x1078, 0x2de3, 0x00c0, 0x2095, 0xa184, 0x0008, 0x0040, + 0x2072, 0x69a0, 0xa184, 0x0600, 0x00c0, 0x2072, 0x1078, 0x2cdf, + 0x0078, 0x2095, 0x69a0, 0xa184, 0x0800, 0x0040, 0x2089, 0x0c7e, + 0x027e, 0x2960, 0x6000, 0xa085, 0x2000, 0x6002, 0x6104, 0xa18d, + 0x0010, 0x6106, 0x027f, 0x0c7f, 0x1078, 0x2de3, 0x00c0, 0x2095, + 0x69a0, 0xa184, 0x0200, 0x0040, 0x2091, 0x1078, 0x2d2e, 0x0078, + 0x2095, 0xa184, 0x0400, 0x00c0, 0x206e, 0x69a0, 0xa184, 0x1000, + 0x0040, 0x20a0, 0x6914, 0xa18c, 0xff00, 0x810f, 0x1078, 0x1d25, + 0x007f, 0x7002, 0xa68c, 0x00e0, 0xa684, 0x0060, 0x0040, 0x20ae, + 0xa086, 0x0060, 0x00c0, 0x20ae, 0xa18d, 0x4000, 0x88ff, 0x0040, + 0x20b3, 0xa18d, 0x0004, 0x795a, 0x69b6, 0x789b, 0x0060, 0x2800, + 0x78aa, 0x789b, 0x0061, 0x6818, 0xa08d, 0x8000, 0xa084, 0x7fff, + 0x691a, 0xa68c, 0x0080, 0x0040, 0x20d2, 0x70cb, 0x0000, 0xa08a, + 0x000d, 0x0050, 0x20d0, 0xa08a, 0x000c, 0x71ca, 0x2001, 0x000c, + 0x800c, 0x71ce, 0x78aa, 0x8008, 0x810c, 0x0040, 0x2c36, 0xa18c, + 0x00f8, 0x00c0, 0x2c36, 0x157e, 0x137e, 0x147e, 0x20a1, 0x012b, + 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, + 0x147f, 0x137f, 0x157f, 0x6814, 0x8007, 0x7882, 0x6d94, 0x7dd6, + 0x7dde, 0x6e98, 0x7ed2, 0x7eda, 0x7830, 0xa084, 0x00c0, 0x00c0, + 0x20fb, 0x0098, 0x2103, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, + 0x306a, 0x0078, 0x1e81, 0x7200, 0xa284, 0x0007, 0xa086, 0x0001, + 0x00c0, 0x2110, 0x781b, 0x004a, 0x1078, 0x306a, 0x0078, 0x2121, + 0x6ab4, 0xa295, 0x2000, 0x7a5a, 0x781b, 0x004a, 0x1078, 0x306a, + 0x7200, 0x2500, 0xa605, 0x0040, 0x2121, 0xa284, 0x0007, 0x1079, + 0x212f, 0xa284, 0x0007, 0xa086, 0x0001, 0x00c0, 0x1e79, 0x6018, + 0x8000, 0x601a, 0xad80, 0x0009, 0x7032, 0x0078, 0x1e79, 0x2137, + 0x347d, 0x347d, 0x346c, 0x347d, 0x2137, 0x346c, 0x2137, 0x1078, + 0x1e2a, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0f7e, 0x2079, 0x3800, + 0x78b0, 0x0f7f, 0xa084, 0x0001, 0x0040, 0x215f, 0x70a0, 0xa086, + 0x0001, 0x00c0, 0x214e, 0x70a2, 0x0078, 0x21e2, 0x70a0, 0xa086, + 0x0005, 0x00c0, 0x215d, 0x70bc, 0x2068, 0x681b, 0x0004, 0x6817, + 0x0000, 0x6820, 0xa085, 0x0008, 0x6822, 0x70a3, 0x0000, 0x157e, + 0x2011, 0x0004, 0x71a0, 0xa186, 0x0001, 0x0040, 0x217d, 0xa186, + 0x0007, 0x00c0, 0x2171, 0x2009, 0x3831, 0x200b, 0x0005, 0x0078, + 0x217d, 0x2009, 0x3813, 0x2104, 0x2009, 0x3812, 0x200a, 0x2009, + 0x3831, 0x200b, 0x0001, 0x0078, 0x217f, 0x70a3, 0x0000, 0x1078, + 0x31f5, 0x20a9, 0x0010, 0x2039, 0x0000, 0x1078, 0x2e9a, 0xa7b8, + 0x0100, 0x0070, 0x218d, 0x0078, 0x2185, 0x7000, 0x0079, 0x2190, + 0x21be, 0x21a7, 0x21a7, 0x219a, 0x21be, 0x21be, 0x21be, 0x2198, + 0x1078, 0x1e2a, 0x2021, 0x3857, 0x2404, 0xa005, 0x0040, 0x21be, + 0xad06, 0x00c0, 0x21a7, 0x6800, 0x2022, 0x0078, 0x21b7, 0x6820, + 0xa084, 0x0001, 0x00c0, 0x21b3, 0x6f14, 0x1078, 0x2f99, 0x1078, + 0x2bf8, 0x0078, 0x21b7, 0x7054, 0x2060, 0x6800, 0x6002, 0x6a1a, + 0x6820, 0xa085, 0x0008, 0x6822, 0x1078, 0x19a4, 0x2021, 0x4280, + 0x1078, 0x21e8, 0x2021, 0x3857, 0x1078, 0x21e8, 0x20a9, 0x0000, + 0x2021, 0x4180, 0x1078, 0x21e8, 0x8420, 0x0070, 0x21d1, 0x0078, + 0x21ca, 0x20a9, 0x0080, 0x2061, 0x3980, 0x6018, 0x6110, 0xa102, + 0x6012, 0x601b, 0x0000, 0xace0, 0x0010, 0x0070, 0x21e1, 0x0078, + 0x21d5, 0x157f, 0x7003, 0x0000, 0x703f, 0x0000, 0x0078, 0x1e79, + 0x047e, 0x2404, 0xa005, 0x0040, 0x21fa, 0x2068, 0x6800, 0x007e, + 0x6a1a, 0x6820, 0xa085, 0x0008, 0x6822, 0x1078, 0x19a4, 0x007f, + 0x0078, 0x21ea, 0x047f, 0x2023, 0x0000, 0x007c, 0xa282, 0x0003, + 0x0050, 0x2204, 0x1078, 0x1e2a, 0x2300, 0x0079, 0x2207, 0x220a, + 0x2271, 0x228e, 0xa282, 0x0002, 0x0040, 0x2210, 0x1078, 0x1e2a, + 0x70a0, 0x70a3, 0x0000, 0x0079, 0x2215, 0x221d, 0x221d, 0x221f, + 0x2251, 0x224f, 0x221d, 0x2251, 0x221d, 0x1078, 0x1e2a, 0x77b4, + 0x1078, 0x2e9a, 0x77b4, 0xa7bc, 0x0f00, 0x1078, 0x2f99, 0x6018, + 0xa005, 0x0040, 0x2248, 0x2021, 0x4280, 0x1078, 0x22a9, 0x0040, + 0x2248, 0x157e, 0x20a9, 0x0000, 0x2021, 0x4180, 0x047e, 0x1078, + 0x22a9, 0x047f, 0x0040, 0x2241, 0x8420, 0x0070, 0x2241, 0x0078, + 0x2236, 0x157f, 0x2021, 0x3857, 0x1078, 0x22a9, 0x0040, 0x2248, + 0x8738, 0xa784, 0x0007, 0x00c0, 0x2225, 0x0078, 0x1e81, 0x0078, + 0x1e81, 0x77b4, 0x1078, 0x2f99, 0x6018, 0xa005, 0x0040, 0x226f, + 0x2021, 0x4280, 0x1078, 0x22a9, 0x0040, 0x226f, 0x157e, 0x20a9, + 0x0000, 0x2021, 0x4180, 0x047e, 0x1078, 0x22a9, 0x047f, 0x0040, + 0x226e, 0x8420, 0x0070, 0x226e, 0x0078, 0x2263, 0x157f, 0x0078, + 0x1e81, 0x2200, 0x0079, 0x2274, 0x2277, 0x2279, 0x2279, 0x1078, + 0x1e2a, 0x2009, 0x0012, 0x70a0, 0xa086, 0x0002, 0x0040, 0x2282, + 0x2009, 0x000e, 0x6818, 0xa084, 0x8000, 0x0040, 0x2288, 0x691a, + 0x70a3, 0x0000, 0x70a7, 0x0001, 0x0078, 0x301c, 0x2200, 0x0079, + 0x2291, 0x2296, 0x2279, 0x2294, 0x1078, 0x1e2a, 0x1078, 0x272c, + 0x7000, 0xa086, 0x0001, 0x00c0, 0x2bce, 0x1078, 0x2c0e, 0x6008, + 0xa084, 0xffef, 0x600a, 0x1078, 0x2bc1, 0x0040, 0x2bce, 0x0078, + 0x1f7b, 0x2404, 0xa005, 0x0040, 0x22cc, 0x2068, 0x2d04, 0x007e, + 0x6814, 0xa706, 0x0040, 0x22b8, 0x2d20, 0x007f, 0x0078, 0x22aa, + 0x007f, 0x2022, 0x681b, 0x0004, 0x6820, 0xa085, 0x0010, 0x6822, + 0x1078, 0x19a4, 0x6010, 0x8001, 0x6012, 0x6008, 0xa084, 0xffef, + 0x600a, 0x1078, 0x2c0e, 0x007c, 0xa085, 0x0001, 0x0078, 0x22cb, + 0x2300, 0x0079, 0x22d3, 0x22d8, 0x22d6, 0x2324, 0x1078, 0x1e2a, + 0x78e4, 0xa005, 0x00d0, 0x22ec, 0x0018, 0x22ec, 0xa084, 0x0007, + 0x0079, 0x22e2, 0x22fd, 0x230a, 0x22f0, 0x22ea, 0x3044, 0x3044, + 0x22ea, 0x2317, 0x1078, 0x1e2a, 0x2001, 0x0003, 0x0078, 0x260b, + 0x6818, 0xa084, 0x8000, 0x0040, 0x22f7, 0x681b, 0x001d, 0x1078, + 0x2e7d, 0x781b, 0x0053, 0x0078, 0x1e79, 0x6818, 0xa084, 0x8000, + 0x0040, 0x2304, 0x681b, 0x001d, 0x1078, 0x2e7d, 0x781b, 0x00de, + 0x0078, 0x1e79, 0x6818, 0xa084, 0x8000, 0x0040, 0x2311, 0x681b, + 0x001d, 0x1078, 0x2e7d, 0x781b, 0x00e5, 0x0078, 0x1e79, 0x6818, + 0xa084, 0x8000, 0x0040, 0x231e, 0x681b, 0x001d, 0x1078, 0x2e7d, + 0x781b, 0x009c, 0x0078, 0x1e79, 0xa584, 0x000f, 0x00c0, 0x2343, + 0x1078, 0x272c, 0x7000, 0x0079, 0x232d, 0x2335, 0x2337, 0x2335, + 0x2bce, 0x2bce, 0x2bce, 0x2bce, 0x2335, 0x1078, 0x1e2a, 0x1078, + 0x2c0e, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x2bc1, 0x0040, + 0x2bce, 0x0078, 0x1f7b, 0x79e4, 0xa005, 0x00d0, 0x22ec, 0x0018, + 0x22ec, 0xa184, 0x0007, 0x0079, 0x234d, 0x235d, 0x2363, 0x2357, + 0x2355, 0x3044, 0x3044, 0x2355, 0x303c, 0x1078, 0x1e2a, 0x1078, + 0x2e85, 0x781b, 0x0053, 0x0078, 0x1e79, 0x1078, 0x2e85, 0x781b, + 0x00de, 0x0078, 0x1e79, 0x1078, 0x2e85, 0x781b, 0x00e5, 0x0078, + 0x1e79, 0x1078, 0x2e85, 0x781b, 0x009c, 0x0078, 0x1e79, 0x2300, + 0x0079, 0x2372, 0x2377, 0x2375, 0x2379, 0x1078, 0x1e2a, 0x0078, + 0x2925, 0x681b, 0x0008, 0x78a3, 0x0000, 0x79e4, 0xa184, 0x0007, + 0x0079, 0x2382, 0x238a, 0x2363, 0x22f0, 0x301c, 0x3044, 0x3044, + 0x238a, 0x303c, 0x1078, 0x1e2a, 0xa282, 0x0005, 0x0050, 0x2392, + 0x1078, 0x1e2a, 0x2300, 0x0079, 0x2395, 0x2398, 0x25bc, 0x25c8, + 0x2200, 0x0079, 0x239b, 0x23b5, 0x23a2, 0x23b5, 0x23a0, 0x25a1, + 0x1078, 0x1e2a, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa082, + 0x0020, 0x0048, 0x2e69, 0xa08a, 0x0004, 0x00c8, 0x2e69, 0x0079, + 0x23b1, 0x2e69, 0x2e69, 0x2e69, 0x2e23, 0x789b, 0x0018, 0x79a8, + 0xa184, 0x0080, 0x0040, 0x23ca, 0xa184, 0x0018, 0x0040, 0x23c6, + 0x0078, 0x2e69, 0x7000, 0xa005, 0x00c0, 0x23c0, 0x2011, 0x0004, + 0x0078, 0x2a57, 0xa184, 0x00ff, 0xa08a, 0x0010, 0x00c8, 0x2e69, + 0x0079, 0x23d2, 0x23e4, 0x23e2, 0x23fc, 0x2400, 0x24b8, 0x2e69, + 0x2e69, 0x24ba, 0x2e69, 0x2e69, 0x259d, 0x259d, 0x2e69, 0x2e69, + 0x2e69, 0x259f, 0x1078, 0x1e2a, 0xa684, 0x1000, 0x0040, 0x23f1, + 0x2001, 0x0300, 0x8000, 0x8000, 0x783a, 0x781b, 0x0099, 0x0078, + 0x1e79, 0x6818, 0xa084, 0x8000, 0x0040, 0x23fa, 0x681b, 0x001d, + 0x0078, 0x23e8, 0x0078, 0x301c, 0x681b, 0x001d, 0x0078, 0x2e75, + 0x6920, 0xa184, 0x8000, 0x00c0, 0x240c, 0x68af, 0x0000, 0x68b3, + 0x0000, 0xa18d, 0x8000, 0x6922, 0xa684, 0x1800, 0x00c0, 0x244b, + 0x6820, 0xa084, 0x0001, 0x00c0, 0x2451, 0x6818, 0xa086, 0x0008, + 0x00c0, 0x241c, 0x681b, 0x0000, 0xa684, 0x0400, 0x0040, 0x24b4, + 0xa684, 0x0080, 0x0040, 0x2447, 0x70cb, 0x0000, 0x6818, 0xa084, + 0x003f, 0xa08a, 0x000d, 0x0050, 0x2447, 0xa08a, 0x000c, 0x71ca, + 0x2001, 0x000c, 0x800c, 0x71ce, 0x789b, 0x0061, 0x78aa, 0x157e, + 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000, 0x80ac, + 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x781b, + 0x0056, 0x0078, 0x1e79, 0xa684, 0x1000, 0x0040, 0x2451, 0x0078, + 0x1e79, 0xa684, 0x0060, 0x0040, 0x24b0, 0xa684, 0x0800, 0x0040, + 0x24b0, 0xa684, 0x8000, 0x00c0, 0x2461, 0x69b0, 0x6aac, 0x0078, + 0x247b, 0xa6b4, 0x7fff, 0x7e5a, 0x6eb6, 0x789b, 0x0074, 0x7aac, + 0x79ac, 0x78ac, 0x801b, 0x00c8, 0x246e, 0x8000, 0xa084, 0x003f, + 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, + 0x2200, 0xa303, 0x68ae, 0xa684, 0x4000, 0x0040, 0x2483, 0xa6b4, + 0xbfff, 0x7e5a, 0x6eb6, 0xa006, 0x1078, 0x353b, 0x6ab0, 0x69ac, + 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0040, 0x2492, 0x2200, 0xa422, + 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x6ba6, 0x7bd6, 0x2300, 0xa405, + 0x00c0, 0x24a2, 0xa6b5, 0x4000, 0x7e5a, 0x6eb6, 0x781b, 0x0065, + 0x0078, 0x1e79, 0x781b, 0x0065, 0x2200, 0xa115, 0x00c0, 0x24ac, + 0x1078, 0x347d, 0x0078, 0x1e79, 0x1078, 0x34b2, 0x0078, 0x1e79, + 0x781b, 0x0068, 0x0078, 0x1e79, 0x781b, 0x0056, 0x0078, 0x1e79, + 0x1078, 0x1e2a, 0x0078, 0x250f, 0x6920, 0xa184, 0x0100, 0x0040, + 0x24ce, 0xa18c, 0xfeff, 0x6922, 0x0c7e, 0x7048, 0x2060, 0x6004, + 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x0078, 0x24fe, 0xa184, 0x0200, + 0x0040, 0x24fe, 0xa18c, 0xfdff, 0x6922, 0x0c7e, 0x7048, 0x2060, + 0x6004, 0xa084, 0xffef, 0x6006, 0x2008, 0x2c48, 0x0c7f, 0xa184, + 0x0008, 0x0040, 0x24fe, 0x1078, 0x2f95, 0x1078, 0x2cdf, 0x88ff, + 0x0040, 0x24fe, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5, + 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x24fa, 0x781b, 0x0053, + 0x0078, 0x1e79, 0x781b, 0x0067, 0x0078, 0x1e79, 0x7e58, 0xa684, + 0x0400, 0x00c0, 0x2507, 0x781b, 0x0056, 0x0078, 0x1e79, 0x781b, + 0x0068, 0x0078, 0x1e79, 0x0078, 0x2e6f, 0x0078, 0x2e6f, 0x2019, + 0x0000, 0x7990, 0xa18c, 0x0007, 0x0040, 0x250d, 0x789b, 0x0010, + 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x00c0, 0x2532, 0x2300, + 0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040, 0x252a, 0x0048, 0x252a, + 0x0078, 0x252c, 0x0078, 0x24bc, 0x24a8, 0x7aa8, 0x00f0, 0x252c, + 0x0078, 0x2518, 0xa284, 0x00f0, 0xa086, 0x0020, 0x00c0, 0x258e, + 0x8318, 0x8318, 0x2300, 0xa102, 0x0040, 0x2542, 0x0048, 0x2542, + 0x0078, 0x258b, 0xa286, 0x0023, 0x0040, 0x250d, 0x681c, 0xa084, + 0xfff1, 0x681e, 0x7e58, 0xa684, 0xfff1, 0xa085, 0x0010, 0x2030, + 0x7e5a, 0x6008, 0xa085, 0x0010, 0x600a, 0x0c7e, 0x7048, 0x2060, + 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0010, 0x0040, 0x2566, + 0x1078, 0x2f95, 0x1078, 0x2de3, 0x0078, 0x2575, 0x0c7e, 0x7048, + 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0008, 0x0040, + 0x24fe, 0x1078, 0x2f95, 0x1078, 0x2cdf, 0x88ff, 0x0040, 0x24fe, + 0x789b, 0x0060, 0x2800, 0x78aa, 0xa6b5, 0x0004, 0x7e5a, 0xa684, + 0x0400, 0x00c0, 0x2587, 0x781b, 0x0053, 0x0078, 0x1e79, 0x781b, + 0x0067, 0x0078, 0x1e79, 0x7aa8, 0x0078, 0x2518, 0x8318, 0x2300, + 0xa102, 0x0040, 0x2597, 0x0048, 0x2597, 0x0078, 0x2518, 0xa284, + 0x0080, 0x00c0, 0x2e75, 0x0078, 0x2e6f, 0x0078, 0x2e75, 0x0078, + 0x2e69, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa08e, 0x0001, + 0x0040, 0x25ac, 0x1078, 0x1e2a, 0x7aa8, 0xa294, 0x00ff, 0x78a8, + 0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x2e69, 0x0079, 0x25b8, + 0x2e69, 0x2c4f, 0x2e69, 0x2d7e, 0xa282, 0x0000, 0x00c0, 0x25c2, + 0x1078, 0x1e2a, 0x1078, 0x2e7d, 0x781b, 0x0067, 0x0078, 0x1e79, + 0xa282, 0x0003, 0x00c0, 0x25ce, 0x1078, 0x1e2a, 0xa484, 0x8000, + 0x00c0, 0x25f1, 0x70a0, 0xa005, 0x0040, 0x25d8, 0x1078, 0x1e2a, + 0x6f14, 0x77b6, 0xa7bc, 0x0f00, 0x1078, 0x2f99, 0x6008, 0xa085, + 0x0021, 0x600a, 0x8738, 0xa784, 0x0007, 0x00c0, 0x25dc, 0x1078, + 0x2e81, 0x70a3, 0x0002, 0x2009, 0x3831, 0x200b, 0x0009, 0x0078, + 0x25f3, 0x1078, 0x2e8d, 0x781b, 0x0067, 0x0078, 0x1e79, 0xa282, + 0x0004, 0x0050, 0x25fd, 0x1078, 0x1e2a, 0x2300, 0x0079, 0x2600, + 0x2603, 0x26df, 0x2707, 0xa286, 0x0003, 0x0040, 0x2609, 0x1078, + 0x1e2a, 0x2001, 0x0000, 0x703a, 0x7000, 0xa084, 0x0007, 0x0079, + 0x2611, 0x2619, 0x261b, 0x261b, 0x27cf, 0x2800, 0x1e81, 0x2800, + 0x2619, 0x1078, 0x1e2a, 0xa684, 0x1000, 0x00c0, 0x2623, 0x1078, + 0x31f5, 0x0040, 0x26b9, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x266b, + 0xa186, 0x0008, 0x00c0, 0x263a, 0x1078, 0x2c0e, 0x6008, 0xa084, + 0xffef, 0x600a, 0x1078, 0x2bc1, 0x0040, 0x266b, 0x1078, 0x31f5, + 0x0078, 0x2652, 0xa186, 0x0028, 0x00c0, 0x266b, 0x1078, 0x31f5, + 0x6008, 0xa084, 0xffef, 0x600a, 0x6018, 0xa005, 0x0040, 0x2652, + 0x8001, 0x601a, 0xa005, 0x0040, 0x2652, 0x8001, 0xa005, 0x0040, + 0x2652, 0x601e, 0x6820, 0xa084, 0x0001, 0x0040, 0x1e81, 0x6820, + 0xa084, 0xfffe, 0x6822, 0x7054, 0x0c7e, 0x2060, 0x6800, 0x6002, + 0x0c7f, 0x6004, 0x6802, 0xa005, 0x2d00, 0x00c0, 0x2668, 0x6002, + 0x6006, 0x0078, 0x1e81, 0x017e, 0x1078, 0x272c, 0x017f, 0xa684, + 0xdf00, 0x681e, 0x682b, 0x0000, 0x6f14, 0x81ff, 0x0040, 0x26b9, + 0xa186, 0x0002, 0x00c0, 0x26b1, 0xa684, 0x0800, 0x00c0, 0x2688, + 0xa684, 0x0060, 0x0040, 0x2688, 0x78d8, 0x7adc, 0x682e, 0x6a32, + 0x6820, 0xa084, 0x0800, 0x00c0, 0x26b9, 0x8717, 0xa294, 0x000f, + 0x8213, 0x8213, 0x8213, 0xa290, 0x3900, 0xa290, 0x0000, 0x221c, + 0x8210, 0x2204, 0xa085, 0x0018, 0x2012, 0x8211, 0xa384, 0x0400, + 0x0040, 0x26ab, 0x68a0, 0xa084, 0x0100, 0x00c0, 0x26ab, 0x1078, + 0x278e, 0x0078, 0x1e81, 0x6008, 0xa085, 0x0002, 0x600a, 0x0078, + 0x26b9, 0xa186, 0x0018, 0x0040, 0x26b9, 0xa186, 0x0014, 0x0040, + 0x1e81, 0x6916, 0x6818, 0xa084, 0x8000, 0x0040, 0x26c1, 0x7038, + 0x681a, 0xa68c, 0xdf00, 0x691e, 0x1078, 0x2bff, 0x1078, 0x2c0e, + 0x00c0, 0x26ce, 0x6008, 0xa084, 0xffef, 0x600a, 0x6820, 0xa084, + 0x0001, 0x00c0, 0x26d7, 0x1078, 0x2bf8, 0x0078, 0x26db, 0x7054, + 0x2060, 0x6800, 0x6002, 0x1078, 0x19a4, 0x0078, 0x1e81, 0xa282, + 0x0004, 0x0048, 0x26e5, 0x1078, 0x1e2a, 0x2200, 0x0079, 0x26e8, + 0x26e3, 0x26ec, 0x26f2, 0x26ec, 0x1078, 0x2e7d, 0x781b, 0x0067, + 0x0078, 0x1e79, 0x7890, 0x8007, 0x8001, 0xa084, 0x0007, 0xa080, + 0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff, 0xa186, 0x0003, 0x0040, + 0x2703, 0x0078, 0x2e69, 0x781b, 0x0068, 0x0078, 0x1e79, 0x6820, + 0xa085, 0x0004, 0x6822, 0x82ff, 0x00c0, 0x2712, 0x1078, 0x2e7d, + 0x0078, 0x2719, 0x8211, 0x0040, 0x2717, 0x1078, 0x1e2a, 0x1078, + 0x2e8d, 0x781b, 0x0067, 0x0078, 0x1e79, 0x1078, 0x306a, 0x7830, + 0xa084, 0x00c0, 0x00c0, 0x2729, 0x0018, 0x2729, 0x791a, 0xa006, + 0x007c, 0xa085, 0x0001, 0x007c, 0xa684, 0x0060, 0x00c0, 0x2736, + 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x278d, 0xa684, 0x0800, + 0x00c0, 0x2746, 0x6998, 0x6a94, 0x692e, 0x6a32, 0x7000, 0xa086, + 0x0006, 0x0040, 0x2745, 0x1078, 0x31f5, 0x007c, 0xa684, 0x0020, + 0x0040, 0x2760, 0xa684, 0x4000, 0x0040, 0x2754, 0x682f, 0x0000, + 0x6833, 0x0000, 0x0078, 0x273e, 0x7038, 0xa005, 0x00c0, 0x275a, + 0x703b, 0x0015, 0x79d8, 0x7adc, 0x692e, 0x6a32, 0x0078, 0x273e, + 0xa684, 0x4000, 0x0040, 0x276a, 0x682f, 0x0000, 0x6833, 0x0000, + 0x0078, 0x273e, 0x7038, 0xa005, 0x00c0, 0x2770, 0x703b, 0x0015, + 0x79d8, 0x7adc, 0x78d0, 0x80fb, 0x00c8, 0x2777, 0x8000, 0xa084, + 0x003f, 0xa108, 0xa291, 0x0000, 0x692e, 0x6a32, 0x2100, 0xa205, + 0x00c0, 0x2784, 0x0078, 0x273e, 0x7000, 0xa086, 0x0006, 0x0040, + 0x278d, 0x1078, 0x353b, 0x0078, 0x273e, 0x007c, 0xa384, 0x0200, + 0x0040, 0x2796, 0x6008, 0xa085, 0x0002, 0x600a, 0x681b, 0x0006, + 0x6a30, 0x692c, 0x6a3e, 0x6942, 0x682f, 0x0003, 0x6833, 0x0000, + 0x6837, 0x0020, 0x6897, 0x0000, 0x689b, 0x0020, 0x7000, 0x0079, + 0x27a9, 0x27b1, 0x27b3, 0x27bc, 0x27b1, 0x27b1, 0x27b1, 0x27b1, + 0x27b1, 0x1078, 0x1e2a, 0x6820, 0xa084, 0x0001, 0x00c0, 0x27bc, + 0x1078, 0x2bf8, 0x0078, 0x27c2, 0x7054, 0x2c50, 0x2060, 0x6800, + 0x6002, 0x2a60, 0x2021, 0x3857, 0x2404, 0xa005, 0x0040, 0x27cb, + 0x2020, 0x0078, 0x27c4, 0x2d22, 0x206b, 0x0000, 0x007c, 0x1078, + 0x2bff, 0x1078, 0x2c0e, 0x682b, 0x0000, 0x789b, 0x000e, 0x6f14, + 0x6817, 0x0002, 0x1078, 0x3575, 0xa684, 0x0800, 0x0040, 0x27e4, + 0x691c, 0xa18d, 0x2000, 0x691e, 0x6818, 0xa084, 0x8000, 0x0040, + 0x27f4, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x27f2, 0x681b, 0x001e, + 0x0078, 0x27f4, 0x681b, 0x0000, 0x2021, 0x3857, 0x6800, 0x2022, + 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x1078, 0x19a4, 0x0078, 0x1e81, + 0x1078, 0x272c, 0x682b, 0x0000, 0x789b, 0x000e, 0x6f14, 0x1078, + 0x306f, 0xa08c, 0x00ff, 0x6916, 0x6818, 0xa084, 0x8000, 0x0040, + 0x2813, 0x7038, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x70a3, 0x0000, + 0x0078, 0x1e81, 0xa006, 0x1078, 0x31f5, 0x6817, 0x0000, 0x681b, + 0x0001, 0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, 0x7000, 0x0079, + 0x2829, 0x2831, 0x2833, 0x2833, 0x2835, 0x2835, 0x2835, 0x2835, + 0x2831, 0x1078, 0x1e2a, 0x1078, 0x2c0e, 0x6008, 0xa084, 0xffef, + 0x600a, 0x0078, 0x2bd9, 0x2300, 0x0079, 0x283e, 0x2841, 0x2843, + 0x287c, 0x1078, 0x1e2a, 0x7000, 0x0079, 0x2846, 0x284e, 0x2850, + 0x2850, 0x286b, 0x2850, 0x2878, 0x286b, 0x284e, 0x1078, 0x1e2a, + 0xa684, 0x0060, 0xa086, 0x0060, 0x00c0, 0x2867, 0xa6b4, 0xffdf, + 0xa6b4, 0xbfff, 0xa6b5, 0x2000, 0x7e5a, 0x681c, 0xa084, 0xffdf, + 0x681e, 0x1078, 0x31f5, 0x1078, 0x347d, 0x0078, 0x301c, 0xa684, + 0x2000, 0x0040, 0x285a, 0x6818, 0xa084, 0x8000, 0x0040, 0x2878, + 0x681b, 0x0015, 0xa684, 0x4000, 0x0040, 0x2878, 0x681b, 0x0007, + 0x781b, 0x00df, 0x0078, 0x1e79, 0x1078, 0x1e2a, 0x2300, 0x0079, + 0x2881, 0x2884, 0x2886, 0x28b9, 0x1078, 0x1e2a, 0x7000, 0x0079, + 0x2889, 0x2891, 0x2893, 0x2893, 0x28ae, 0x2893, 0x28b5, 0x28ae, + 0x2891, 0x1078, 0x1e2a, 0xa684, 0x0060, 0xa086, 0x0060, 0x00c0, + 0x28aa, 0xa6b4, 0xffbf, 0xa6b4, 0xbfff, 0xa6b5, 0x2000, 0x7e5a, + 0x681c, 0xa084, 0xffbf, 0x681e, 0x1078, 0x31f5, 0x1078, 0x347d, + 0x0078, 0x301c, 0xa684, 0x2000, 0x0040, 0x289d, 0x6818, 0xa084, + 0x8000, 0x0040, 0x28b5, 0x681b, 0x0007, 0x781b, 0x00e6, 0x0078, + 0x1e79, 0x6820, 0xa085, 0x0004, 0x6822, 0x1078, 0x2fe7, 0xa6b5, + 0x0800, 0x1078, 0x2e7d, 0x781b, 0x0067, 0x0078, 0x1e79, 0x2300, + 0x0079, 0x28ca, 0x28cd, 0x28cf, 0x28d1, 0x1078, 0x1e2a, 0x1078, + 0x1e2a, 0x782b, 0x3009, 0xa684, 0x0400, 0x00c0, 0x28eb, 0x789b, + 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x79e4, 0xa184, + 0x0020, 0x00c0, 0x28e7, 0x2001, 0x0014, 0x0078, 0x260b, 0xa184, + 0x0007, 0x0079, 0x291b, 0x7a90, 0xa294, 0x0007, 0x789b, 0x0060, + 0x79a8, 0x81ff, 0x0040, 0x2919, 0x789b, 0x0010, 0x7ba8, 0xa384, + 0x0001, 0x00c0, 0x2912, 0x7ba8, 0x7ba8, 0xa386, 0x0001, 0x00c0, + 0x2905, 0x2009, 0xfff7, 0x0078, 0x290b, 0xa386, 0x0003, 0x00c0, + 0x2912, 0x2009, 0xffef, 0x0c7e, 0x7048, 0x2060, 0x6004, 0xa104, + 0x6006, 0x0c7f, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, + 0x785a, 0x0078, 0x301c, 0x22fd, 0x230a, 0x3024, 0x3024, 0x2923, + 0x2923, 0x2923, 0x3024, 0x1078, 0x1e2a, 0x79e4, 0xa184, 0x0030, + 0x00c0, 0x293b, 0x70a0, 0xa086, 0x0002, 0x00c0, 0x2933, 0x2011, + 0x0002, 0x0078, 0x21fe, 0x6818, 0xa085, 0x8000, 0x681a, 0x2001, + 0x0014, 0x0078, 0x260b, 0xa18c, 0x0007, 0xa186, 0x0002, 0x00c0, + 0x3044, 0xa684, 0x0080, 0x0040, 0x2970, 0x71c8, 0x81ff, 0x0040, + 0x2970, 0xa182, 0x000d, 0x00d0, 0x2951, 0x70cb, 0x0000, 0x0078, + 0x2956, 0xa182, 0x000c, 0x70ca, 0x2009, 0x000c, 0x789b, 0x0061, + 0x79aa, 0x157e, 0x137e, 0x147e, 0x70cc, 0x8114, 0xa210, 0x72ce, + 0xa080, 0x000b, 0xad00, 0x2098, 0x20a1, 0x012b, 0x789b, 0x0000, + 0x8108, 0x81ac, 0x53a6, 0x147f, 0x137f, 0x157f, 0x0078, 0x3024, + 0xa684, 0x0400, 0x00c0, 0x29b1, 0x6820, 0xa084, 0x0001, 0x0040, + 0x3024, 0xa68c, 0x0060, 0xa684, 0x0060, 0x0040, 0x2985, 0xa086, + 0x0060, 0x00c0, 0x2985, 0xa18d, 0x4000, 0xa18c, 0xfffb, 0x795a, + 0x69b6, 0x789b, 0x0060, 0x78ab, 0x0000, 0x789b, 0x0061, 0x6818, + 0xa085, 0x8000, 0x681a, 0x78aa, 0x8008, 0x810c, 0x0040, 0x2c36, + 0xa18c, 0x00f8, 0x00c0, 0x2c36, 0x157e, 0x137e, 0x147e, 0x20a1, + 0x012b, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, + 0x53a6, 0x147f, 0x137f, 0x157f, 0x6814, 0x8007, 0x7882, 0x0078, + 0x3024, 0x6818, 0xa084, 0x8000, 0x0040, 0x29b8, 0x681b, 0x0008, + 0x781b, 0x00da, 0x0078, 0x1e79, 0x2300, 0x0079, 0x29bf, 0x29c4, + 0x2a47, 0x29c2, 0x1078, 0x1e2a, 0x7000, 0xa084, 0x0007, 0x0079, + 0x29c9, 0x29d1, 0x29d3, 0x29ef, 0x29d1, 0x29d1, 0x1e81, 0x29d1, + 0x29d1, 0x1078, 0x1e2a, 0x6920, 0xa18d, 0x0001, 0x6922, 0x6800, + 0x6006, 0xa005, 0x00c0, 0x29dd, 0x6002, 0x681c, 0xa084, 0x000e, + 0x0040, 0x29e9, 0x7014, 0x68ba, 0x712c, 0xa188, 0x4180, 0x0078, + 0x29eb, 0x2009, 0x4280, 0x2104, 0x6802, 0x2d0a, 0x7156, 0x6920, + 0xa184, 0x8000, 0x00c0, 0x29fb, 0x68af, 0x0000, 0x68b3, 0x0000, + 0xa18d, 0x8000, 0x6922, 0x6eb6, 0xa684, 0x0060, 0x0040, 0x2a45, + 0xa684, 0x0800, 0x00c0, 0x2a0c, 0x6894, 0x68a6, 0x6898, 0x68aa, + 0x1078, 0x31f5, 0x0078, 0x2a45, 0xa684, 0x0020, 0x0040, 0x2a19, + 0xa006, 0x1078, 0x353b, 0x79d8, 0x7adc, 0x69aa, 0x6aa6, 0x0078, + 0x2a1f, 0x1078, 0x2fa6, 0x69aa, 0x6aa6, 0x1078, 0x353b, 0xa684, + 0x8000, 0x0040, 0x2a45, 0xa684, 0x7fff, 0x68b6, 0x789b, 0x0074, + 0x1078, 0x306f, 0x2010, 0x1078, 0x306f, 0x2008, 0xa684, 0x0020, + 0x00c0, 0x2a3d, 0x1078, 0x306f, 0x801b, 0x00c8, 0x2a38, 0x8000, + 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, + 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x0078, 0x1e81, 0x0078, + 0x2e75, 0x7033, 0x0000, 0xa282, 0x0006, 0x0050, 0x2a51, 0x1078, + 0x1e2a, 0x2300, 0x0079, 0x2a54, 0x2a57, 0x2a7d, 0x2aa1, 0x2200, + 0x0079, 0x2a5a, 0x2a60, 0x2e75, 0x2a62, 0x2a60, 0x2acb, 0x2b1c, + 0x1078, 0x1e2a, 0x7003, 0x0005, 0x2001, 0x4290, 0x2068, 0x703e, + 0x157e, 0x20a9, 0x002f, 0x2003, 0x0000, 0x8000, 0x0070, 0x2a72, + 0x0078, 0x2a6b, 0x157f, 0x6817, 0x0000, 0x68b7, 0x0700, 0x6823, + 0x0800, 0x6827, 0x0003, 0x0078, 0x2e69, 0x7000, 0xa086, 0x0001, + 0x00c0, 0x2a8a, 0x1078, 0x2c0e, 0x1078, 0x31f5, 0x7034, 0x600a, + 0x0078, 0x2a8f, 0x7000, 0xa086, 0x0003, 0x0040, 0x2a84, 0x7003, + 0x0005, 0x2001, 0x4290, 0x2068, 0x703e, 0x7032, 0x2200, 0x0079, + 0x2a99, 0x2e75, 0x2a9f, 0x2a9f, 0x2acb, 0x2a9f, 0x2e75, 0x1078, + 0x1e2a, 0x7000, 0xa086, 0x0001, 0x00c0, 0x2aae, 0x1078, 0x2c0e, + 0x1078, 0x31f5, 0x7034, 0x600a, 0x0078, 0x2ab3, 0x7000, 0xa086, + 0x0003, 0x0040, 0x2aa8, 0x7003, 0x0005, 0x2001, 0x4290, 0x2068, + 0x703e, 0x7032, 0x2200, 0x0079, 0x2abd, 0x2ac5, 0x2ac3, 0x2ac3, + 0x2ac5, 0x2ac3, 0x2ac5, 0x1078, 0x1e2a, 0x1078, 0x2e8d, 0x781b, + 0x0067, 0x0078, 0x1e79, 0x7000, 0xa086, 0x0001, 0x00c0, 0x2ad8, + 0x1078, 0x2c0e, 0x1078, 0x31f5, 0x7034, 0x600a, 0x0078, 0x2add, + 0x7000, 0xa086, 0x0003, 0x0040, 0x2ad2, 0x7003, 0x0002, 0x7a80, + 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x0007, 0xa215, + 0x2069, 0x4280, 0x2d04, 0x2d08, 0x7156, 0x2068, 0xa005, 0x0040, + 0x2af8, 0x6814, 0xa206, 0x0040, 0x2b11, 0x6800, 0x0078, 0x2aeb, + 0x7003, 0x0005, 0x2001, 0x4290, 0x2068, 0x703e, 0x7032, 0x157e, + 0x20a9, 0x002f, 0x2003, 0x0000, 0x8000, 0x0070, 0x2b09, 0x0078, + 0x2b02, 0x157f, 0x6a16, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, + 0x0003, 0x6eb4, 0x7e5a, 0x6820, 0xa084, 0x0c00, 0x0040, 0x2b7a, + 0x1078, 0x2e85, 0x0078, 0x2b7a, 0x7000, 0xa086, 0x0001, 0x00c0, + 0x2b29, 0x1078, 0x2c0e, 0x1078, 0x31f5, 0x7034, 0x600a, 0x0078, + 0x2b2e, 0x7000, 0xa086, 0x0003, 0x0040, 0x2b23, 0x7003, 0x0002, + 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x0007, + 0xa215, 0x79a8, 0x79a8, 0xa18c, 0x00ff, 0xa1e8, 0x4180, 0x2d04, + 0x2d08, 0x7156, 0x2068, 0xa005, 0x0040, 0x2b4d, 0x6814, 0xa206, + 0x0040, 0x2b65, 0x6800, 0x0078, 0x2b40, 0x7003, 0x0005, 0x2001, + 0x4290, 0x2068, 0x703e, 0x157e, 0x20a9, 0x002f, 0x2003, 0x0000, + 0x8000, 0x0070, 0x2b5d, 0x0078, 0x2b56, 0x157f, 0x6a16, 0x68b7, + 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x7e5a, 0x6820, + 0xa084, 0x0c00, 0x0040, 0x2b7a, 0xa084, 0x0800, 0x0040, 0x2b74, + 0x1078, 0x2e89, 0x0078, 0x2b7a, 0x1078, 0x2e85, 0x70bf, 0x0000, + 0x0078, 0x2b7a, 0x027e, 0x8207, 0xa084, 0x000f, 0x8003, 0x8003, + 0x8003, 0xa080, 0x3900, 0x2060, 0x704a, 0x6000, 0x704e, 0x6004, + 0x7052, 0xa684, 0x0060, 0x0040, 0x2b93, 0x68a8, 0x78d2, 0x78da, + 0x68a4, 0x78d6, 0x78de, 0x077f, 0x1078, 0x2f99, 0x2009, 0x0068, + 0xa684, 0x0008, 0x0040, 0x2b9e, 0x2009, 0x0067, 0xa6b5, 0x2000, + 0x7e5a, 0x791a, 0xa684, 0x0060, 0x0040, 0x2bb4, 0xa684, 0x0800, + 0x00c0, 0x2bae, 0x1078, 0x347d, 0x0078, 0x2bb4, 0xa684, 0x4000, + 0x00c0, 0x2bb4, 0x1078, 0x340e, 0x2d00, 0x703e, 0x8207, 0xa084, + 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x3900, 0x2048, 0x0078, + 0x1e79, 0x6020, 0xa005, 0x0040, 0x2bcd, 0x8001, 0x6022, 0x6008, + 0xa085, 0x0008, 0x600a, 0x7010, 0x6026, 0x007c, 0xa006, 0x1078, + 0x31f5, 0x6817, 0x0000, 0x681b, 0x0001, 0x6823, 0x0040, 0x681f, + 0x0100, 0x7000, 0xa084, 0x0007, 0x0079, 0x2bde, 0x2be6, 0x2be8, + 0x2be8, 0x2bf4, 0x2bf0, 0x2be6, 0x2bf0, 0x2be6, 0x1078, 0x1e2a, + 0x1078, 0x2bff, 0x1078, 0x2bf8, 0x1078, 0x19a4, 0x0078, 0x1e81, + 0x70a3, 0x0000, 0x0078, 0x1e81, 0x681b, 0x0000, 0x0078, 0x27cf, + 0x6800, 0xa005, 0x00c0, 0x2bfd, 0x6002, 0x6006, 0x007c, 0x6010, + 0xa005, 0x0040, 0x2c08, 0x8001, 0x00d0, 0x2c08, 0x1078, 0x1e2a, + 0x6012, 0x6008, 0xa084, 0xffef, 0x600a, 0x007c, 0x6018, 0xa005, + 0x0040, 0x2c14, 0x8001, 0x601a, 0x007c, 0x1078, 0x306a, 0x6818, + 0xa084, 0x8000, 0x0040, 0x2c1e, 0x681b, 0x0018, 0x0078, 0x2c43, + 0x1078, 0x306a, 0x6818, 0xa084, 0x8000, 0x0040, 0x2c29, 0x681b, + 0x0019, 0x0078, 0x2c43, 0x1078, 0x306a, 0x6818, 0xa084, 0x8000, + 0x0040, 0x2c34, 0x681b, 0x001a, 0x0078, 0x2c43, 0x1078, 0x306a, + 0x681b, 0x0003, 0x0078, 0x2c43, 0x6818, 0xa084, 0x8000, 0x0040, + 0x2c43, 0x681b, 0x0005, 0x681f, 0x0000, 0x6823, 0x0020, 0x1078, + 0x2bff, 0x1078, 0x2bf8, 0x1078, 0x19a4, 0x0078, 0x1e81, 0xa282, + 0x0003, 0x00c0, 0x2e69, 0x7da8, 0xa5ac, 0x00ff, 0x7ea8, 0xa6b4, + 0x00ff, 0x6920, 0xa18d, 0x0080, 0x6922, 0xa184, 0x0100, 0x0040, + 0x2c92, 0xa18c, 0xfeff, 0x6922, 0xa6b4, 0x00ff, 0x0040, 0x2c7c, + 0xa682, 0x000c, 0x0048, 0x2c70, 0x0040, 0x2c70, 0x2031, 0x000c, + 0x852b, 0x852b, 0x1078, 0x2f18, 0x0040, 0x2c7a, 0x1078, 0x2d4a, + 0x0078, 0x2c85, 0x1078, 0x2ed3, 0x0c7e, 0x2960, 0x6004, 0xa084, + 0xfff5, 0x6006, 0x1078, 0x2d6e, 0x0c7f, 0x7e58, 0xa684, 0x0400, + 0x00c0, 0x2c8e, 0x781b, 0x0056, 0x0078, 0x1e79, 0x781b, 0x0068, + 0x0078, 0x1e79, 0x0c7e, 0x7048, 0x2060, 0x6100, 0xa18c, 0x1000, + 0x0040, 0x2cd2, 0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x000c, + 0x0048, 0x2ca6, 0x0040, 0x2ca6, 0x2011, 0x000c, 0x2600, 0xa202, + 0x00c8, 0x2cab, 0x2230, 0x6208, 0xa294, 0x00ff, 0x7018, 0xa086, + 0x0028, 0x00c0, 0x2cbb, 0xa282, 0x0019, 0x00c8, 0x2cc1, 0x2011, + 0x0019, 0x0078, 0x2cc1, 0xa282, 0x000c, 0x00c8, 0x2cc1, 0x2011, + 0x000c, 0x2200, 0xa502, 0x00c8, 0x2cc6, 0x2228, 0x1078, 0x2ed7, + 0x852b, 0x852b, 0x1078, 0x2f18, 0x0040, 0x2cd2, 0x1078, 0x2d4a, + 0x0078, 0x2cd6, 0x1078, 0x2ed3, 0x1078, 0x2d6e, 0x7858, 0xa085, + 0x0004, 0x785a, 0x0c7f, 0x781b, 0x0067, 0x0078, 0x1e79, 0x0c7e, + 0x2960, 0x6000, 0xa084, 0x1000, 0x00c0, 0x2cf7, 0x6010, 0xa084, + 0x000f, 0x00c0, 0x2cf1, 0x6104, 0xa18c, 0xfff5, 0x6106, 0x0c7f, + 0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, 0x2d1e, 0x68a0, + 0xa084, 0x0200, 0x00c0, 0x2cf1, 0x6208, 0xa294, 0x00ff, 0x7018, + 0xa086, 0x0028, 0x00c0, 0x2d0c, 0xa282, 0x0019, 0x00c8, 0x2d12, + 0x2011, 0x0019, 0x0078, 0x2d12, 0xa282, 0x000c, 0x00c8, 0x2d12, + 0x2011, 0x000c, 0x6308, 0x831f, 0xa39c, 0x00ff, 0xa382, 0x000c, + 0x0048, 0x2d1e, 0x0040, 0x2d1e, 0x2019, 0x000c, 0x78ab, 0x0001, + 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, + 0x6820, 0xa085, 0x0100, 0x6822, 0x0c7f, 0x007c, 0x0c7e, 0x2960, + 0x6104, 0xa18c, 0xfff5, 0x6106, 0x2011, 0x0032, 0x2019, 0x0000, + 0x0078, 0x2d3a, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, + 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xa085, 0x0100, 0x6822, + 0x0c7f, 0x007c, 0x0c7e, 0x7148, 0x2160, 0x2008, 0xa084, 0xfff0, + 0xa635, 0x7e86, 0x6018, 0x789a, 0x7eae, 0x6612, 0x78a4, 0xa084, + 0xfff8, 0xa18c, 0x0007, 0xa105, 0x78a6, 0x6016, 0x788a, 0xa6b4, + 0x000f, 0x8637, 0x8204, 0x8004, 0xa084, 0x00ff, 0xa605, 0x600e, + 0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x007c, 0x0c7e, 0x7048, + 0x2060, 0x6018, 0x789a, 0x78a4, 0xa084, 0xfff0, 0x78a6, 0x6012, + 0x7884, 0xa084, 0xfff0, 0x7886, 0x0c7f, 0x007c, 0xa282, 0x0002, + 0x00c0, 0x2e69, 0x7aa8, 0x6920, 0xa18d, 0x0080, 0x6922, 0xa184, + 0x0200, 0x0040, 0x2dc3, 0xa18c, 0xfdff, 0x6922, 0xa294, 0x00ff, + 0xa282, 0x0002, 0x00c8, 0x2e69, 0x1078, 0x2e0a, 0x1078, 0x2d6e, + 0xa980, 0x0001, 0x200c, 0x1078, 0x2f95, 0x1078, 0x2cdf, 0x88ff, + 0x0040, 0x2db6, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5, + 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2db2, 0x781b, 0x0053, + 0x0078, 0x1e79, 0x781b, 0x0067, 0x0078, 0x1e79, 0x7e58, 0xa684, + 0x0400, 0x00c0, 0x2dbf, 0x781b, 0x0056, 0x0078, 0x1e79, 0x781b, + 0x0068, 0x0078, 0x1e79, 0xa282, 0x0002, 0x00c8, 0x2dcb, 0xa284, + 0x0001, 0x0040, 0x2dd5, 0x7148, 0xa188, 0x0000, 0x210c, 0xa18c, + 0x2000, 0x00c0, 0x2dd5, 0x2011, 0x0000, 0x1078, 0x2ec5, 0x1078, + 0x2e0a, 0x1078, 0x2d6e, 0x7858, 0xa085, 0x0004, 0x785a, 0x781b, + 0x0067, 0x0078, 0x1e79, 0x0c7e, 0x027e, 0x2960, 0x6000, 0x2011, + 0x0001, 0xa084, 0x2000, 0x00c0, 0x2dfa, 0x6014, 0xa084, 0x0040, + 0x00c0, 0x2df8, 0xa18c, 0xffef, 0x6106, 0xa006, 0x0078, 0x2e07, + 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, + 0x7aaa, 0xa8c0, 0x0004, 0x6820, 0xa085, 0x0200, 0x6822, 0x027f, + 0x0c7f, 0x007c, 0x0c7e, 0x7048, 0x2060, 0x82ff, 0x0040, 0x2e12, + 0x2011, 0x0040, 0x6018, 0xa080, 0x0002, 0x789a, 0x78a4, 0xa084, + 0xffbf, 0xa205, 0x78a6, 0x6016, 0x788a, 0x6004, 0xa084, 0xffef, + 0x6006, 0x0c7f, 0x007c, 0xa684, 0x0020, 0x0040, 0x2e65, 0x7888, + 0xa084, 0x0040, 0x0040, 0x2e65, 0x7bb8, 0xa384, 0x003f, 0x831b, + 0x00c8, 0x2e33, 0x8000, 0xa005, 0x0040, 0x2e4c, 0x831b, 0x00c8, + 0x2e3c, 0x8001, 0x0040, 0x2e61, 0xa684, 0x4000, 0x0040, 0x2e4c, + 0x78b8, 0x801b, 0x00c8, 0x2e45, 0x8000, 0xa084, 0x003f, 0x00c0, + 0x2e61, 0xa6b4, 0xbfff, 0x7e5a, 0x79d8, 0x7adc, 0x2001, 0x0001, + 0xa108, 0x00c8, 0x2e55, 0xa291, 0x0000, 0x79d2, 0x79da, 0x7ad6, + 0x7ade, 0x1078, 0x353b, 0x781b, 0x0065, 0x1078, 0x340e, 0x0078, + 0x1e79, 0x781b, 0x0065, 0x0078, 0x1e79, 0x781b, 0x0068, 0x0078, + 0x1e79, 0x1078, 0x2e91, 0x781b, 0x0067, 0x0078, 0x1e79, 0x1078, + 0x2e7d, 0x781b, 0x0067, 0x0078, 0x1e79, 0x6827, 0x0002, 0x1078, + 0x2e85, 0x781b, 0x0067, 0x0078, 0x1e79, 0x2001, 0x0005, 0x0078, + 0x2e93, 0x2001, 0x000c, 0x0078, 0x2e93, 0x2001, 0x0006, 0x0078, + 0x2e93, 0x2001, 0x000d, 0x0078, 0x2e93, 0x2001, 0x0009, 0x0078, + 0x2e93, 0x2001, 0x0007, 0x789b, 0x007e, 0x78aa, 0xa6b5, 0x0008, + 0x7e5a, 0x007c, 0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b, + 0x8703, 0xa0e0, 0x3900, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184, + 0x000f, 0x0040, 0x2eb3, 0xa184, 0xfff0, 0x78a6, 0x6012, 0x6004, + 0xa085, 0x0008, 0x6006, 0x8738, 0x8738, 0x7f9a, 0x79a4, 0xa184, + 0x0040, 0x0040, 0x2ec3, 0xa184, 0xffbf, 0x78a6, 0x6016, 0x6004, + 0xa085, 0x0010, 0x6006, 0x077f, 0x007c, 0x789b, 0x0010, 0x78ab, + 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060, + 0x78ab, 0x0004, 0x007c, 0x2031, 0x0000, 0x2029, 0x0032, 0x789b, + 0x0010, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, + 0x7eaa, 0x789b, 0x0060, 0x78ab, 0x0005, 0x007c, 0x157e, 0x8007, + 0xa084, 0x00ff, 0x8003, 0x8003, 0xa080, 0x0020, 0x789a, 0x79a4, + 0xa18c, 0xfff0, 0x2001, 0x3846, 0x2004, 0xa082, 0x0028, 0x0040, + 0x2f01, 0x2021, 0x2f7c, 0x2019, 0x0014, 0x20a9, 0x000c, 0x0078, + 0x2f07, 0x2021, 0x2f88, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011, + 0x0064, 0x2404, 0xa084, 0xfff0, 0xa106, 0x0040, 0x2f16, 0x8420, + 0x2300, 0xa210, 0x0070, 0x2f16, 0x0078, 0x2f09, 0x157f, 0x007c, + 0x157e, 0x2011, 0x3846, 0x2214, 0xa282, 0x0032, 0x0048, 0x2f2c, + 0x0040, 0x2f30, 0x2021, 0x2f6e, 0x2019, 0x0011, 0x20a9, 0x000e, + 0x2011, 0x0032, 0x0078, 0x2f42, 0xa282, 0x0028, 0x0040, 0x2f3a, + 0x2021, 0x2f7c, 0x2019, 0x0014, 0x20a9, 0x000c, 0x2011, 0x0064, + 0x0078, 0x2f42, 0x2021, 0x2f88, 0x2019, 0x0019, 0x20a9, 0x000d, + 0x2011, 0x0064, 0x2200, 0xa502, 0x0040, 0x2f52, 0x0048, 0x2f52, + 0x8420, 0x2300, 0xa210, 0x0070, 0x2f4f, 0x0078, 0x2f42, 0x157f, + 0xa006, 0x007c, 0x157f, 0x7a08, 0xa582, 0x00c8, 0x00c8, 0x2f5d, + 0xa285, 0x0040, 0x780a, 0x0078, 0x2f5d, 0x78ec, 0xa084, 0x0300, + 0x0040, 0x2f6b, 0x2404, 0xa09e, 0x2002, 0x00c0, 0x2f6b, 0x2001, + 0x2101, 0x0078, 0x2f6c, 0x2404, 0xa005, 0x007c, 0x2002, 0x3002, + 0x3202, 0x4203, 0x4403, 0x5404, 0x5604, 0x6605, 0x6805, 0x7806, + 0x7a06, 0x0a07, 0x0c07, 0x0e07, 0x3202, 0x4202, 0x5202, 0x6202, + 0x7202, 0x6605, 0x7605, 0x7805, 0x7a05, 0x7c05, 0x7e05, 0x7f05, + 0x2202, 0x3202, 0x4202, 0x5202, 0x5404, 0x6404, 0x7404, 0x7604, + 0x7804, 0x7a04, 0x7c04, 0x7e04, 0x7f04, 0x789b, 0x0010, 0xa046, + 0x007c, 0xa784, 0x0f00, 0x800c, 0xa784, 0x0007, 0x8003, 0x8003, + 0x8003, 0x8003, 0xa105, 0xa0e0, 0x3980, 0x007c, 0x79d8, 0x7adc, + 0x78d0, 0x801b, 0x00c8, 0x2fad, 0x8000, 0xa084, 0x003f, 0xa108, + 0xa291, 0x0000, 0x007c, 0x0f7e, 0x2079, 0x0100, 0x2009, 0x3840, + 0x2091, 0x8000, 0x2104, 0x0079, 0x2fbd, 0x2fe3, 0x2fc7, 0x2fc7, + 0x2fc7, 0x2fc7, 0x2fc7, 0x2fc7, 0x2fc5, 0x1078, 0x1e2a, 0x784b, + 0x0004, 0x68b4, 0xa085, 0x4000, 0x68b6, 0x7858, 0xa085, 0x4000, + 0x785a, 0x7830, 0xa084, 0x0080, 0x00c0, 0x2fe3, 0x0018, 0x2fe3, + 0x681c, 0xa084, 0x0020, 0x00c0, 0x2fe1, 0x781b, 0x00df, 0x0078, + 0x2fe3, 0x781b, 0x00e6, 0x2091, 0x8001, 0x0f7f, 0x007c, 0x0c7e, + 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e0, + 0x3900, 0x6004, 0xa084, 0x000a, 0x00c0, 0x301a, 0x6108, 0xa194, + 0xff00, 0x0040, 0x301a, 0xa18c, 0x00ff, 0x2001, 0x0019, 0xa106, + 0x0040, 0x3009, 0x2001, 0x0032, 0xa106, 0x0040, 0x300d, 0x0078, + 0x3011, 0x2009, 0x0020, 0x0078, 0x3013, 0x2009, 0x003f, 0x0078, + 0x3013, 0x2011, 0x0000, 0x2100, 0xa205, 0x600a, 0x6004, 0xa085, + 0x0002, 0x6006, 0x0c7f, 0x007c, 0x781b, 0x0068, 0x0078, 0x1e79, + 0x781b, 0x0067, 0x0078, 0x1e79, 0x781b, 0x0056, 0x0078, 0x1e79, + 0x781b, 0x0053, 0x0078, 0x1e79, 0x781b, 0x00df, 0x0078, 0x1e79, + 0x781b, 0x00de, 0x0078, 0x1e79, 0x781b, 0x00e6, 0x0078, 0x1e79, + 0x781b, 0x00e5, 0x0078, 0x1e79, 0x781b, 0x009d, 0x0078, 0x1e79, + 0x781b, 0x009c, 0x0078, 0x1e79, 0x6818, 0xa084, 0x8000, 0x0040, + 0x304b, 0x681b, 0x001d, 0x70a3, 0x0001, 0x781b, 0x0047, 0x0078, + 0x1e79, 0x007e, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x3068, 0x7808, + 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, + 0xa084, 0x0021, 0x0040, 0x3068, 0x7808, 0xa085, 0x0002, 0x780a, + 0x007f, 0x007c, 0x7808, 0xa085, 0x0002, 0x780a, 0x007c, 0x7830, + 0xa084, 0x0040, 0x00c0, 0x306f, 0x0098, 0x3078, 0x78ac, 0x007c, + 0x7808, 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, + 0x78ec, 0xa084, 0x0021, 0x0040, 0x3087, 0x0098, 0x3085, 0x78ac, + 0x007e, 0x7808, 0xa085, 0x0002, 0x780a, 0x007f, 0x007c, 0xa784, + 0x0070, 0x0040, 0x309b, 0x0c7e, 0x2d60, 0x2f68, 0x1078, 0x1dd5, + 0x2d78, 0x2c68, 0x0c7f, 0xa784, 0x0008, 0x0040, 0x30a8, 0x784b, + 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x1e81, 0x0078, 0x301c, + 0xa784, 0x0004, 0x0040, 0x30db, 0x78b8, 0xa084, 0x4001, 0x0040, + 0x30db, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x1e81, + 0x78e4, 0xa084, 0x0007, 0xa086, 0x0001, 0x00c0, 0x30db, 0x78c0, + 0xa685, 0x4800, 0x2030, 0x7e5a, 0x781b, 0x00e6, 0x0078, 0x1e79, + 0x784b, 0x0008, 0x6818, 0xa084, 0x8000, 0x0040, 0x30d7, 0x681b, + 0x0015, 0xa684, 0x4000, 0x0040, 0x30d7, 0x681b, 0x0007, 0x781b, + 0x00df, 0x0078, 0x1e79, 0x681b, 0x0003, 0x7858, 0xa084, 0x3f00, + 0x681e, 0x682f, 0x0000, 0x6833, 0x0000, 0x784b, 0x0008, 0x78e4, + 0xa005, 0x00d0, 0x22ec, 0xa084, 0x0020, 0x0040, 0x22ec, 0x0018, + 0x22ec, 0x0078, 0x2e6f, 0x6b14, 0x8307, 0xa084, 0x000f, 0x8003, + 0x8003, 0x8003, 0xa080, 0x3900, 0x2060, 0x2048, 0x704a, 0x6000, + 0x704e, 0x6004, 0x7052, 0x2a60, 0x007c, 0x0020, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0062, + 0x0009, 0x0014, 0x0014, 0x9848, 0x0014, 0x0014, 0x98f9, 0x98e9, + 0x0014, 0x0014, 0x0080, 0x00c0, 0x0100, 0x0402, 0x2008, 0xf880, + 0x0018, 0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014, 0xa200, 0x8838, + 0x3806, 0x8839, 0x28c2, 0x9cc2, 0xa805, 0x0864, 0xa83d, 0x3008, + 0x28c1, 0x9cc2, 0xa201, 0x300c, 0x2847, 0x8161, 0x846a, 0x8000, + 0x84a4, 0x1856, 0x883a, 0xa808, 0x28e2, 0x9c9f, 0xa8f3, 0x0864, + 0xa82b, 0x300c, 0xa801, 0x3008, 0x28e1, 0x9c9f, 0x280d, 0xa204, + 0x64c0, 0x67a0, 0x6fc0, 0x1814, 0x883b, 0x7023, 0x8576, 0x8677, + 0xa80f, 0x786e, 0x883e, 0xa80c, 0x282b, 0xa205, 0x64a0, 0x67a0, + 0x6fc0, 0x1814, 0x883b, 0x7023, 0x8576, 0x8677, 0xa801, 0x883e, + 0x206b, 0x28c1, 0x9cc2, 0x2044, 0x2103, 0x20a2, 0x2081, 0xa8dc, + 0xa207, 0x2901, 0xa80a, 0x0014, 0xa203, 0x8000, 0x85a4, 0x1872, + 0x879a, 0x883c, 0x1fe2, 0xf601, 0xa208, 0x856e, 0x866f, 0x0704, + 0x3008, 0x9c9f, 0x0014, 0xa202, 0x8000, 0x85a4, 0x3009, 0x84a8, + 0x19e2, 0xf848, 0x8174, 0x86eb, 0x85eb, 0x872e, 0x87a9, 0x883f, + 0x08e6, 0xa8f1, 0xf861, 0xa8e8, 0xf801, 0x0014, 0xf881, 0x0016, + 0x85b2, 0x80f0, 0x9532, 0xfaa2, 0x1de2, 0x0014, 0x8532, 0xf221, + 0x0014, 0x1de2, 0x84a8, 0xd6e0, 0x1fe6, 0x0014, 0xa206, 0x6865, + 0x817e, 0x842a, 0x1dc1, 0x8823, 0x0016, 0x6042, 0x8008, 0xa8fa, + 0x8000, 0x84a4, 0x8160, 0x842a, 0xf021, 0x3008, 0x84a8, 0x11d6, + 0x7042, 0x20dd, 0x0011, 0x20d4, 0x8822, 0x0016, 0x8000, 0x2848, + 0x1011, 0xa8fc, 0x3008, 0x8000, 0xa000, 0x2802, 0x1011, 0xa8fd, + 0xa883, 0x3008, 0x283d, 0x1011, 0xa8fd, 0xa209, 0x0017, 0x300c, + 0x8000, 0x85a4, 0x1de2, 0xdac1, 0x0014, 0xd301, 0x0014, 0x26e0, + 0x873a, 0xfaa2, 0x19f2, 0x1fe2, 0x0014, 0xa20b, 0x0014, 0xa20d, + 0x3806, 0x0210, 0x9ccc, 0x0704, 0x0000, 0x127e, 0x2091, 0x2200, + 0x2049, 0x31f5, 0x7000, 0x7204, 0xa205, 0x720c, 0xa215, 0x7008, + 0xa084, 0xfff7, 0xa205, 0x0040, 0x3207, 0x1078, 0x3280, 0x127f, + 0x2000, 0x007c, 0x6428, 0x84ff, 0x0040, 0x3236, 0x2c70, 0x7004, + 0xa0bc, 0x000f, 0xa7b8, 0x3246, 0x273c, 0x87fb, 0x00c0, 0x3224, + 0x0048, 0x321c, 0x1078, 0x1e2a, 0x609c, 0xa075, 0x0040, 0x3236, + 0x0078, 0x320f, 0x2039, 0x323b, 0x2704, 0xae68, 0x6808, 0xa630, + 0x680c, 0xa529, 0x8421, 0x0040, 0x3236, 0x8738, 0x2704, 0xa005, + 0x00c0, 0x3225, 0x709c, 0xa075, 0x00c0, 0x320f, 0x007c, 0x0000, + 0x0005, 0x0009, 0x000d, 0x0011, 0x0015, 0x0019, 0x001d, 0x0000, + 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0000, 0x323b, + 0x3238, 0x0000, 0x0000, 0x8000, 0x0000, 0x323b, 0x0000, 0x3243, + 0x3240, 0x0000, 0x0000, 0x0000, 0x0000, 0x3243, 0x0000, 0x323e, + 0x323e, 0x0000, 0x0000, 0x8000, 0x0000, 0x323e, 0x0000, 0x3244, + 0x3244, 0x0000, 0x0000, 0x0000, 0x0000, 0x3244, 0x127e, 0x2091, + 0x2200, 0x2079, 0x3800, 0x2071, 0x0010, 0x7007, 0x000a, 0x7007, + 0x0002, 0x7003, 0x0000, 0x2071, 0x0020, 0x7007, 0x000a, 0x7007, + 0x0002, 0x7003, 0x0000, 0x2049, 0x0000, 0x127f, 0x2000, 0x007c, + 0x2049, 0x3280, 0x2019, 0x0000, 0x7004, 0x8004, 0x00c8, 0x32b2, + 0x7007, 0x0012, 0x7108, 0x7008, 0xa106, 0x00c0, 0x328a, 0xa184, + 0x01e0, 0x0040, 0x3295, 0x1078, 0x1e2a, 0xa184, 0x4000, 0x00c0, + 0x328a, 0xa19c, 0x300c, 0xa386, 0x2004, 0x0040, 0x32a7, 0xa386, + 0x0008, 0x0040, 0x32b2, 0xa386, 0x200c, 0x00c0, 0x328a, 0x7200, + 0x8204, 0x0048, 0x32b2, 0x730c, 0xa384, 0x00ff, 0x0040, 0x32b2, + 0x1078, 0x1e2a, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xa084, + 0x0008, 0x00c0, 0x32b6, 0x7007, 0x0012, 0x7108, 0x8103, 0x0048, + 0x32bb, 0x7003, 0x0000, 0x2049, 0x0000, 0x007c, 0x107e, 0x007e, + 0x127e, 0x157e, 0x2091, 0x2200, 0x7108, 0x1078, 0x32d6, 0x157f, + 0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c, 0x7204, 0x7500, + 0x730c, 0xa384, 0x0300, 0x00c0, 0x3315, 0xa184, 0x0060, 0x00c0, + 0x334e, 0x7008, 0x7108, 0xa106, 0x00c0, 0x32e1, 0xa184, 0x01e0, + 0x00c0, 0x334e, 0xa184, 0x4000, 0x00c0, 0x32e1, 0xa986, 0x353b, + 0x00c0, 0x3309, 0xa19c, 0x300c, 0xa386, 0x2004, 0x0040, 0x3300, + 0xa386, 0x0008, 0x0040, 0x3309, 0xa386, 0x200c, 0x00c0, 0x32e1, + 0x7200, 0x8204, 0x0048, 0x3309, 0x730c, 0xa384, 0x00ff, 0x00c0, + 0x3315, 0xa184, 0x0007, 0x0079, 0x330d, 0x3317, 0x3342, 0x3315, + 0x3342, 0x3315, 0x339b, 0x3315, 0x3399, 0x1078, 0x1e2a, 0x7007, + 0x0002, 0x8aff, 0x00c0, 0x3320, 0x2049, 0x0000, 0x0078, 0x3324, + 0x1078, 0x3512, 0x00c0, 0x3320, 0x2704, 0xac00, 0xa088, 0x0002, + 0x2104, 0x8108, 0x6892, 0x2104, 0x688e, 0x8a07, 0x077e, 0x007e, + 0x6004, 0xa084, 0x0008, 0x0040, 0x3339, 0xa7ba, 0x3240, 0x0078, + 0x333b, 0xa7ba, 0x3238, 0x007f, 0xa73d, 0x2c00, 0x6886, 0x6f8a, + 0x077f, 0x007c, 0x7007, 0x0002, 0x8aff, 0x00c0, 0x3349, 0x0078, + 0x334d, 0x1078, 0x3512, 0x00c0, 0x3349, 0x007c, 0x7108, 0x7008, + 0xa106, 0x00c0, 0x334e, 0xa184, 0x4000, 0x00c0, 0x334e, 0x7007, + 0x0012, 0x7108, 0x7008, 0xa106, 0x00c0, 0x3359, 0xa184, 0x4000, + 0x00c0, 0x3359, 0x00e0, 0x3362, 0x2091, 0x6000, 0x00e0, 0x3366, + 0x2091, 0x6000, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xa084, + 0x0008, 0x00c0, 0x336e, 0x7007, 0x0012, 0x7108, 0x8103, 0x0048, + 0x3373, 0x7003, 0x0000, 0x7000, 0xa005, 0x00c0, 0x3387, 0x7004, + 0xa005, 0x00c0, 0x3387, 0x700c, 0xa005, 0x0040, 0x3389, 0x0078, + 0x336a, 0x2049, 0x0000, 0x1078, 0x2fb3, 0x6818, 0xa084, 0x8000, + 0x0040, 0x3394, 0x681b, 0x0002, 0x007c, 0x1078, 0x1e2a, 0x1078, + 0x1e2a, 0x1078, 0x33f9, 0x7210, 0x7114, 0x700c, 0xa09c, 0x00ff, + 0x2800, 0xa300, 0xa211, 0xa189, 0x0000, 0x1078, 0x33f9, 0x2704, + 0x2c58, 0xac60, 0x6308, 0x2200, 0xa322, 0x630c, 0x2100, 0xa31b, + 0x2400, 0xa305, 0x0040, 0x33be, 0x00c8, 0x33be, 0x8412, 0x8210, + 0x830a, 0xa189, 0x0000, 0x2b60, 0x0078, 0x33a5, 0x2b60, 0x8a07, + 0x007e, 0x6004, 0xa084, 0x0008, 0x0040, 0x33ca, 0xa7ba, 0x3240, + 0x0078, 0x33cc, 0xa7ba, 0x3238, 0x007f, 0xa73d, 0x2c00, 0x6886, + 0x6f8a, 0x6c92, 0x6b8e, 0x1078, 0x3280, 0x007c, 0x8738, 0x2704, + 0xa005, 0x00c0, 0x33e9, 0x609c, 0xa005, 0x0040, 0x33f6, 0x2060, + 0x6004, 0xa084, 0x000f, 0xa080, 0x3246, 0x203c, 0x87fb, 0x1040, + 0x1e2a, 0x8a51, 0x0040, 0x33f5, 0x7008, 0x7508, 0xa52e, 0x00c0, + 0x33ec, 0xa084, 0x0003, 0xa086, 0x0003, 0x007c, 0x2051, 0x0000, + 0x007c, 0x8a50, 0x8739, 0x2704, 0xa004, 0x00c0, 0x340d, 0x6000, + 0xa064, 0x00c0, 0x3404, 0x2d60, 0x6004, 0xa084, 0x000f, 0xa080, + 0x3256, 0x203c, 0x87fb, 0x1040, 0x1e2a, 0x007c, 0x127e, 0x0d7e, + 0x2091, 0x2200, 0x0d7f, 0x6884, 0x2060, 0x6888, 0x6b8c, 0x6c90, + 0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, 0x007e, 0x6804, 0xa084, + 0x0008, 0x007f, 0x0040, 0x3428, 0xa0b8, 0x3240, 0x0078, 0x342a, + 0xa0b8, 0x3238, 0x7e08, 0xa6b5, 0x000c, 0x681c, 0xa084, 0x0040, + 0x0040, 0x3434, 0xa6b5, 0x0001, 0x7007, 0x0004, 0x7004, 0xa084, + 0x0004, 0x00c0, 0x3436, 0x2400, 0xa305, 0x00c0, 0x3441, 0x0078, + 0x3465, 0x2c58, 0x2704, 0x6104, 0xac60, 0x6000, 0xa400, 0x701a, + 0x6004, 0xa301, 0x701e, 0xa184, 0x0008, 0x0040, 0x3455, 0x6010, + 0xa001, 0x7022, 0x6014, 0xa001, 0x7026, 0x6208, 0x2400, 0xa202, + 0x7012, 0x620c, 0x2300, 0xa203, 0x7016, 0x7602, 0x7007, 0x0001, + 0x2b60, 0x1078, 0x33d6, 0x0078, 0x3467, 0x1078, 0x3512, 0x00c0, + 0x3465, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, + 0x0d7f, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x3473, + 0x7003, 0x0008, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, 0x2091, + 0x2200, 0x0d7f, 0x2049, 0x347d, 0x7007, 0x0004, 0x7004, 0xa084, + 0x0004, 0x00c0, 0x3486, 0x7e08, 0xa6b5, 0x000c, 0x681c, 0xa084, + 0x0020, 0x00c0, 0x3495, 0xa6b5, 0x0001, 0x6828, 0x2050, 0x2d60, + 0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x3246, 0x273c, 0x87fb, 0x00c0, + 0x34ab, 0x0048, 0x34a5, 0x1078, 0x1e2a, 0x689c, 0xa065, 0x0040, + 0x34af, 0x0078, 0x3498, 0x1078, 0x3512, 0x00c0, 0x34ab, 0x127f, + 0x2000, 0x007c, 0x127e, 0x007e, 0x017e, 0x0d7e, 0x2091, 0x2200, + 0x0d7f, 0x037f, 0x047f, 0x7e08, 0xa6b5, 0x000c, 0x681c, 0xa084, + 0x0040, 0x0040, 0x34c5, 0xa6b5, 0x0001, 0x2049, 0x34b2, 0x6828, + 0xa055, 0x0040, 0x350f, 0x2d70, 0x2e60, 0x7004, 0xa0bc, 0x000f, + 0xa7b8, 0x3246, 0x273c, 0x87fb, 0x00c0, 0x34e1, 0x0048, 0x34da, + 0x1078, 0x1e2a, 0x709c, 0xa075, 0x2060, 0x0040, 0x350f, 0x0078, + 0x34cd, 0x2704, 0xae68, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0048, + 0x34fc, 0x8a51, 0x00c0, 0x34ee, 0x1078, 0x1e2a, 0x8738, 0x2704, + 0xa005, 0x00c0, 0x34e2, 0x709c, 0xa075, 0x2060, 0x0040, 0x350f, + 0x2039, 0x3238, 0x0078, 0x34cd, 0x8422, 0x8420, 0x831a, 0xa399, + 0x0000, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, 0x00c8, + 0x350b, 0x1078, 0x1e2a, 0x2071, 0x0020, 0x0078, 0x3434, 0x127f, + 0x2000, 0x007c, 0x7008, 0x7508, 0xa52e, 0x00c0, 0x3512, 0xa084, + 0x0003, 0xa086, 0x0003, 0x0040, 0x353a, 0x2704, 0xac08, 0x2104, + 0x701a, 0x8108, 0x2104, 0x701e, 0x8108, 0x2104, 0x7012, 0x8108, + 0x2104, 0x7016, 0x6004, 0xa084, 0x0008, 0x0040, 0x3535, 0x8108, + 0x2104, 0x7022, 0x8108, 0x2104, 0x7026, 0x7602, 0x7007, 0x0001, + 0x1078, 0x33d6, 0x007c, 0x127e, 0x007e, 0x0d7e, 0x2091, 0x2200, + 0x2049, 0x353b, 0x0d7f, 0x087f, 0x7108, 0x7008, 0xa106, 0x00c0, + 0x3544, 0xa184, 0x4000, 0x00c0, 0x3544, 0xa184, 0x0003, 0x00c0, + 0x355b, 0x6828, 0xa005, 0x0040, 0x3569, 0x0020, 0x355b, 0x1078, + 0x339b, 0x0078, 0x3569, 0x00a0, 0x3562, 0x7108, 0x1078, 0x32d6, + 0x0078, 0x3544, 0x7007, 0x0010, 0x00a0, 0x3564, 0x7108, 0x1078, + 0x32d6, 0x7008, 0xa086, 0x0008, 0x00c0, 0x3544, 0x7003, 0x0000, + 0x2049, 0x0000, 0x127f, 0x2000, 0x007c, 0x127e, 0x147e, 0x137e, + 0x157e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049, 0x3575, 0xad80, + 0x0011, 0x20a0, 0x2099, 0x0031, 0x700c, 0xa084, 0x00ff, 0x682a, + 0x7007, 0x0008, 0x7007, 0x0002, 0x7003, 0x0001, 0x0040, 0x3593, + 0x8000, 0x80ac, 0x53a5, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, + 0x00c0, 0x3595, 0x2049, 0x0000, 0x7003, 0x0000, 0x157f, 0x137f, + 0x147f, 0x127f, 0x2000, 0x007c, 0x2091, 0x6000, 0x78b0, 0xa005, + 0x0040, 0x35b9, 0x797c, 0x70d0, 0xa106, 0x00c0, 0x35b9, 0x7804, + 0xa005, 0x0040, 0x35b9, 0x7807, 0x0000, 0x0068, 0x35b9, 0x2091, + 0x4080, 0x7820, 0x8001, 0x7822, 0x00c0, 0x3619, 0x7824, 0x7822, + 0x2091, 0x8000, 0x78e0, 0xa005, 0x0040, 0x35e6, 0x78c4, 0xa005, + 0x00c0, 0x35e6, 0x3a10, 0xa284, 0x0002, 0x00c0, 0x35d6, 0x78c7, + 0x0007, 0x2009, 0xff01, 0x200a, 0x0078, 0x35e6, 0xa284, 0x0001, + 0x00c0, 0x35de, 0x78df, 0x0000, 0x0078, 0x35e6, 0x78dc, 0xa005, + 0x00c0, 0x35e6, 0x78c7, 0x0008, 0x78df, 0x0001, 0x2069, 0x3840, + 0x6800, 0xa084, 0x0007, 0x0040, 0x35fd, 0xa086, 0x0002, 0x0040, + 0x35fd, 0x6830, 0xa00d, 0x0040, 0x35fd, 0x2104, 0xa005, 0x0040, + 0x35fd, 0x8001, 0x200a, 0x0040, 0x36bb, 0x7848, 0xa005, 0x0040, + 0x3619, 0x8001, 0x784a, 0x00c0, 0x3619, 0x0f7e, 0x2079, 0x0100, + 0x1078, 0x306a, 0x0f7f, 0x1078, 0x1c74, 0x68c4, 0xa005, 0x0040, + 0x3619, 0x8001, 0x68c6, 0x00c0, 0x3619, 0x68a3, 0x0000, 0x68a7, + 0x0001, 0x1078, 0x3620, 0x1078, 0x3645, 0x2091, 0x8001, 0x007c, + 0x7834, 0x8001, 0x7836, 0x00c0, 0x3644, 0x7838, 0x7836, 0x2091, + 0x8000, 0x7844, 0xa005, 0x00c0, 0x362f, 0x2001, 0x0101, 0x8001, + 0x7846, 0xa080, 0x4180, 0x2040, 0x2004, 0xa065, 0x0040, 0x3644, + 0x6024, 0xa005, 0x0040, 0x3640, 0x8001, 0x6026, 0x0040, 0x3674, + 0x6000, 0x2c40, 0x0078, 0x3635, 0x007c, 0x7828, 0x8001, 0x782a, + 0x00c0, 0x3673, 0x782c, 0x782a, 0x7830, 0xa005, 0x00c0, 0x3652, + 0x2001, 0x0080, 0x8001, 0x7832, 0x8003, 0x8003, 0x8003, 0x8003, + 0xa090, 0x3980, 0xa298, 0x0002, 0x2304, 0xa084, 0x0008, 0x0040, + 0x3673, 0xa290, 0x0009, 0x2204, 0xa005, 0x0040, 0x366b, 0x8001, + 0x2012, 0x00c0, 0x3673, 0x2304, 0xa084, 0xfff7, 0xa085, 0x0080, + 0x201a, 0x1078, 0x1c74, 0x007c, 0x2069, 0x3840, 0x6800, 0xa005, + 0x0040, 0x367e, 0x683c, 0xac06, 0x0040, 0x36bb, 0x601b, 0x0006, + 0x60b4, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, + 0x0060, 0x6022, 0x6000, 0x2042, 0x6714, 0x6fb6, 0x1078, 0x183c, + 0x6818, 0xa005, 0x0040, 0x3696, 0x8001, 0x681a, 0x6808, 0xa084, + 0xffef, 0x680a, 0x6810, 0x8001, 0x00d0, 0x36a0, 0x1078, 0x1e2a, + 0x6812, 0x602f, 0x0000, 0x6033, 0x0000, 0x2c68, 0x1078, 0x19a4, + 0x2069, 0x3840, 0x2001, 0x0006, 0x68a2, 0x7944, 0xa184, 0x0100, + 0x00c0, 0x36b6, 0x69ba, 0x2001, 0x0004, 0x68a2, 0x1078, 0x1c6f, + 0x2091, 0x8001, 0x007c, 0x2009, 0x384f, 0x2164, 0x2069, 0x0100, + 0x1078, 0x1dd5, 0x601b, 0x0006, 0x6858, 0xa084, 0x3f00, 0x601e, + 0x6020, 0xa084, 0x00ff, 0xa085, 0x0048, 0x6022, 0x602f, 0x0000, + 0x6033, 0x0000, 0x6830, 0xa084, 0x0040, 0x0040, 0x36f7, 0x684b, + 0x0004, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0004, 0x0040, 0x36e4, + 0x0070, 0x36e4, 0x0078, 0x36db, 0x684b, 0x0009, 0x20a9, 0x0014, + 0x6848, 0xa084, 0x0001, 0x0040, 0x36f1, 0x0070, 0x36f1, 0x0078, + 0x36e8, 0x20a9, 0x00fa, 0x0070, 0x36f7, 0x0078, 0x36f3, 0x6808, + 0xa084, 0xfffd, 0x680a, 0x681b, 0x0047, 0x2009, 0x3868, 0x200b, + 0x0007, 0x784c, 0x784a, 0x2091, 0x8001, 0x007c, 0x2079, 0x3800, + 0x1078, 0x3731, 0x1078, 0x3715, 0x1078, 0x3723, 0x7833, 0x0000, + 0x7847, 0x0000, 0x784b, 0x0000, 0x007c, 0x2019, 0x000c, 0x2011, + 0x3846, 0x2204, 0xa086, 0x003c, 0x0040, 0x3720, 0x2019, 0x0008, + 0x7b2a, 0x7b2e, 0x007c, 0x2019, 0x0039, 0x2011, 0x3846, 0x2204, + 0xa086, 0x003c, 0x0040, 0x372e, 0x2019, 0x0027, 0x7b36, 0x7b3a, + 0x007c, 0x2019, 0x3971, 0x2011, 0x3846, 0x2204, 0xa086, 0x003c, + 0x0040, 0x373c, 0x2019, 0x2626, 0x7b22, 0x7b26, 0x783f, 0x0000, + 0x7843, 0x000a, 0x007c, 0xe0c5 +}; + +#endif /* RELOAD_FIRMWARE */ + +unsigned short risc_code_length01 = 0x2744; diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h index b6acbd57aa88..22c361a9ea92 100644 --- a/drivers/scsi/scsi.h +++ b/drivers/scsi/scsi.h @@ -521,7 +521,7 @@ static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors if (req->bh){ req->buffer = bh->b_data; return SCpnt; - }; + } DEVICE_OFF(req->rq_dev); if (req->sem != NULL) { up(req->sem); diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index e3453d1e9ddb..42da5ecc237f 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -298,7 +298,7 @@ static int ioctl_command(Scsi_Device *dev, void *buffer) /* * the scsi_ioctl() function differs from most ioctls in that it does - * not take a major/minor number as the dev filed. Rather, it takes + * not take a major/minor number as the dev field. Rather, it takes * a pointer to a scsi_devices[] element, a structure. */ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e68d085ee7aa..3bca2934e71f 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -106,28 +106,23 @@ static int sd_open(struct inode * inode, struct file * filp) */ while (rscsi_disks[target].device->busy) - barrier(); + barrier(); if(rscsi_disks[target].device->removable) { check_disk_change(inode->i_rdev); /* * If the drive is empty, just let the open fail. */ - if ( !rscsi_disks[target].ready ) { + if ( !rscsi_disks[target].ready ) return -ENXIO; - } /* * Similarly, if the device has the write protect tab set, * have the open fail if the user expects to be able to write * to the thing. */ - if ( (rscsi_disks[target].write_prot) && (filp->f_mode & 2) ) { + if ( (rscsi_disks[target].write_prot) && (filp->f_mode & 2) ) return -EROFS; - } - - if(!rscsi_disks[target].device->access_count) - sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0); } /* @@ -137,6 +132,10 @@ static int sd_open(struct inode * inode, struct file * filp) if(sd_sizes[MINOR(inode->i_rdev)] == 0) return -ENXIO; + if(rscsi_disks[target].device->removable) + if(!rscsi_disks[target].device->access_count) + sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0); + rscsi_disks[target].device->access_count++; if (rscsi_disks[target].device->host->hostt->usage_count) (*rscsi_disks[target].device->host->hostt->usage_count)++; @@ -208,9 +207,9 @@ static void sd_geninit (struct gendisk *ignored) } /* - * rw_intr is the interrupt routine for the device driver. It will - * be notified on the end of a SCSI read / write, and - * will take on of several actions based on success or failure. + * rw_intr is the interrupt routine for the device driver. + * It will be notified on the end of a SCSI read / write, and + * will take one of several actions based on success or failure. */ static void rw_intr (Scsi_Cmnd *SCpnt) diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 26d2b36e729d..229bc908781e 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -554,21 +554,30 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne return (0); } + case BLKRAGET: + if (!arg) + return -EINVAL; + err = verify_area(VERIFY_WRITE, (int *) arg, sizeof(int)); + if (err) + return err; + put_user(read_ahead[MAJOR(inode->i_rdev)], (int *) arg); + return 0; + case BLKRASET: - { - if(!suser()) return -EACCES; - if(!(inode->i_rdev)) return -EINVAL; - if(arg > 0xff) return -EINVAL; + if(!suser()) + return -EACCES; + if(!(inode->i_rdev)) + return -EINVAL; + if(arg > 0xff) + return -EINVAL; read_ahead[MAJOR(inode->i_rdev)] = arg; return 0; - RO_IOCTLS(dev,arg); - } + + RO_IOCTLS(dev,arg); case CDROMRESET: - { - invalidate_buffers(MKDEV(MAJOR(inode->i_rdev),MINOR(inode->i_rdev))); + invalidate_buffers(inode->i_rdev); return 0; - } default: return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index b0aa76a1448d..18d2e40fe421 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -11,7 +11,7 @@ Copyright 1992 - 1996 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Thu May 2 19:41:34 1996 by makisara@kai.makisara.fi + Last modified: Tue May 14 17:58:12 1996 by makisara@kai.makisara.fi Some small formal changes - aeb, 950809 */ @@ -530,8 +530,6 @@ scsi_tape_open(struct inode * inode, struct file * filp) printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n", dev, STp->current_mode, mode); #endif - /* if (!STp->modes[mode].defined) - return (-ENXIO); */ new_session = TRUE; STp->current_mode = mode; } @@ -570,12 +568,20 @@ scsi_tape_open(struct inode * inode, struct file * filp) STp->nbr_waits = STp->nbr_finished = 0; #endif + if (scsi_tapes[dev].device->host->hostt->usage_count) + (*scsi_tapes[dev].device->host->hostt->usage_count)++; + if(st_template.usage_count) (*st_template.usage_count)++; + memset ((void *) &cmd[0], 0, 10); cmd[0] = TEST_UNIT_READY; SCpnt = st_do_scsi(NULL, STp, cmd, 0, ST_LONG_TIMEOUT, MAX_READY_RETRIES); - if (!SCpnt) + if (!SCpnt) { + if (scsi_tapes[dev].device->host->hostt->usage_count) + (*scsi_tapes[dev].device->host->hostt->usage_count)--; + if(st_template.usage_count) (*st_template.usage_count)--; return (-EBUSY); + } if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && (SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ @@ -619,9 +625,6 @@ scsi_tape_open(struct inode * inode, struct file * filp) STp->partition = STp->new_partition = 0; STp->door_locked = ST_UNLOCKED; STp->in_use = 1; - if (scsi_tapes[dev].device->host->hostt->usage_count) - (*scsi_tapes[dev].device->host->hostt->usage_count)++; - if(st_template.usage_count) (*st_template.usage_count)++; return 0; } @@ -698,6 +701,9 @@ scsi_tape_open(struct inode * inode, struct file * filp) STp->block_size); (STp->buffer)->in_use = 0; STp->buffer = NULL; + if (scsi_tapes[dev].device->host->hostt->usage_count) + (*scsi_tapes[dev].device->host->hostt->usage_count)--; + if(st_template.usage_count) (*st_template.usage_count)--; return (-EIO); } STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; @@ -726,6 +732,9 @@ scsi_tape_open(struct inode * inode, struct file * filp) if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) { (STp->buffer)->in_use = 0; STp->buffer = NULL; + if (scsi_tapes[dev].device->host->hostt->usage_count) + (*scsi_tapes[dev].device->host->hostt->usage_count)--; + if(st_template.usage_count) (*st_template.usage_count)--; return (-EROFS); } } @@ -741,6 +750,9 @@ scsi_tape_open(struct inode * inode, struct file * filp) if ((STp->partition = find_partition(inode)) < 0) { (STp->buffer)->in_use = 0; STp->buffer = NULL; + if (scsi_tapes[dev].device->host->hostt->usage_count) + (*scsi_tapes[dev].device->host->hostt->usage_count)--; + if(st_template.usage_count) (*st_template.usage_count)--; return STp->partition; } STp->new_partition = STp->partition; @@ -754,6 +766,9 @@ scsi_tape_open(struct inode * inode, struct file * filp) (i = set_mode_densblk(inode, STp, STm)) < 0) { (STp->buffer)->in_use = 0; STp->buffer = NULL; + if (scsi_tapes[dev].device->host->hostt->usage_count) + (*scsi_tapes[dev].device->host->hostt->usage_count)--; + if(st_template.usage_count) (*st_template.usage_count)--; return i; } if (STp->default_drvbuffer != 0xff) { @@ -764,9 +779,6 @@ scsi_tape_open(struct inode * inode, struct file * filp) } STp->in_use = 1; - if (scsi_tapes[dev].device->host->hostt->usage_count) - (*scsi_tapes[dev].device->host->hostt->usage_count)++; - if(st_template.usage_count) (*st_template.usage_count)++; return 0; } @@ -3050,5 +3062,6 @@ void cleanup_module( void) } } st_template.dev_max = 0; + printk(KERN_INFO "st: Unloaded.\n"); } #endif /* MODULE */ diff --git a/fs/Config.in b/fs/Config.in index 8ac62ab2972a..208856183fe8 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -35,11 +35,10 @@ fi tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS -# AFFS disabled until they can get that BYTE/WORD/LONG crap sorted out -#tristate 'Amiga FFS filesystem support (EXPERIMENTAL)' CONFIG_AFFS_FS -#if [ "$CONFIG_AFFS_FS" = "y" -o "$CONFIG_AFFS_FS" = "m" ]; then -# define_bool CONFIG_AMIGA_PARTITION y -#fi +tristate 'Amiga FFS filesystem support (EXPERIMENTAL)' CONFIG_AFFS_FS +if [ "$CONFIG_AFFS_FS" = "y" -o "$CONFIG_AFFS_FS" = "m" ]; then + define_bool CONFIG_AMIGA_PARTITION y +fi tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS if [ "$CONFIG_UFS_FS" != "n" ]; then bool "BSD disklabel (FreeBSD partition tables) support" CONFIG_BSD_DISKLABEL diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c index cc986de29cfe..63d76a86ee3e 100644 --- a/fs/affs/amigaffs.c +++ b/fs/affs/amigaffs.c @@ -1,7 +1,7 @@ /* * linux/fs/affs/amigaffs.c * - * (c) 1996 Hans-Joachim Widmaier - rewritten + * (c) 1996 Hans-Joachim Widmaier - Rewritten * * (C) 1993 Ray Burr - Amiga FFS filesystem. * @@ -29,10 +29,10 @@ extern struct timezone sys_tz; is returned. */ int -affs_find_next_hash_entry(int hsize, void *dir_data, ULONG *hash_pos) +affs_find_next_hash_entry(int hsize, void *dir_data, int *hash_pos) { struct dir_front *dir_front = dir_data; - ULONG i; + int i; for (i = *hash_pos; i < hsize; i++) if (dir_front->hashtable[i] != 0) @@ -67,11 +67,11 @@ affs_get_file_name(int bsize, void *fh_data, char **name) /* Find the predecessor in the hash chain */ int -affs_fix_hash_pred(struct inode *startino, int startoffset, LONG key, LONG newkey) +affs_fix_hash_pred(struct inode *startino, int startoffset, int key, int newkey) { struct buffer_head *bh = NULL; - ULONG nextkey; - LONG ptype, stype; + int nextkey; + int ptype, stype; int retval; nextkey = startino->i_ino; @@ -92,9 +92,9 @@ affs_fix_hash_pred(struct inode *startino, int startoffset, LONG key, LONG newke affs_brelse(bh); break; } - nextkey = htonl(((ULONG *)bh->b_data)[startoffset]); + nextkey = htonl(((__u32 *)bh->b_data)[startoffset]); if (nextkey == key) { - ((ULONG *)bh->b_data)[startoffset] = newkey; + ((__u32 *)bh->b_data)[startoffset] = newkey; affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5); mark_buffer_dirty(bh,1); affs_brelse(bh); @@ -112,13 +112,13 @@ affs_fix_hash_pred(struct inode *startino, int startoffset, LONG key, LONG newke /* Remove inode from link chain */ int -affs_fix_link_pred(struct inode *startino, LONG key, LONG newkey) +affs_fix_link_pred(struct inode *startino, int key, int newkey) { struct buffer_head *bh = NULL; - ULONG nextkey; - ULONG offset; - LONG etype = 0; - LONG ptype, stype; + int nextkey; + int offset; + int etype = 0; + int ptype, stype; int retval; offset = AFFS_I2BSIZE(startino) / 4 - 10; @@ -150,7 +150,7 @@ affs_fix_link_pred(struct inode *startino, LONG key, LONG newkey) retval = -EPERM; break; } - nextkey = htonl(((ULONG *)bh->b_data)[offset]); + nextkey = htonl(((__u32 *)bh->b_data)[offset]); if (nextkey == key) { FILE_END(bh->b_data,startino)->link_chain = newkey; affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5); @@ -172,17 +172,17 @@ affs_fix_link_pred(struct inode *startino, LONG key, LONG newkey) (which lets us calculate the block size). Returns non-zero if the block is not consistent. */ -ULONG -affs_checksum_block(int bsize, void *data, LONG *ptype, LONG *stype) +__u32 +affs_checksum_block(int bsize, void *data, int *ptype, int *stype) { - ULONG sum; - ULONG *p; + __u32 sum; + __u32 *p; bsize /= 4; if (ptype) - *ptype = htonl(((LONG *)data)[0]); + *ptype = htonl(((__s32 *)data)[0]); if (stype) - *stype = htonl(((LONG *)data)[bsize - 1]); + *stype = htonl(((__s32 *)data)[bsize - 1]); sum = 0; p = data; @@ -194,20 +194,20 @@ affs_checksum_block(int bsize, void *data, LONG *ptype, LONG *stype) void affs_fix_checksum(int bsize, void *data, int cspos) { - ULONG ocs; - ULONG cs; + __u32 ocs; + __u32 cs; cs = affs_checksum_block(bsize,data,NULL,NULL); - ocs = htonl (((ULONG *)data)[cspos]); + ocs = htonl (((__u32 *)data)[cspos]); ocs -= cs; - ((ULONG *)data)[cspos] = htonl(ocs); + ((__u32 *)data)[cspos] = htonl(ocs); } void secs_to_datestamp(int secs, struct DateStamp *ds) { - ULONG days; - ULONG minute; + __u32 days; + __u32 minute; secs -= sys_tz.tz_minuteswest * 60 +((8 * 365 + 2) * 24 * 60 * 60); if (secs < 0) @@ -223,7 +223,7 @@ secs_to_datestamp(int secs, struct DateStamp *ds) } int -prot_to_mode(ULONG prot) +prot_to_mode(__u32 prot) { int mode = 0; @@ -249,10 +249,10 @@ prot_to_mode(ULONG prot) return mode; } -ULONG +unsigned int mode_to_prot(int mode) { - ULONG prot = 0; + unsigned int prot = 0; if (mode & S_IXUSR) prot |= FIBF_SCRIPT; diff --git a/fs/affs/bitmap.c b/fs/affs/bitmap.c index 50fbaead10b4..00fd83eacf66 100644 --- a/fs/affs/bitmap.c +++ b/fs/affs/bitmap.c @@ -2,24 +2,28 @@ * linux/fs/affs/bitmap.c * * (c) 1996 Hans-Joachim Widmaier + * + * + * bitmap.c contains the code that handles all bitmap related stuff - + * block allocation, deallocation, calculation of free space. */ -/* bitmap.c contains the code that handles the inode and block bitmaps */ - #include #include #include #include #include -#include #include +#include #include +/* This is, of course, shamelessly stolen from fs/minix */ + static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 }; int -affs_count_free_bits(int blocksize, const UBYTE *data) +affs_count_free_bits(int blocksize, const char *data) { int free; int i; @@ -42,94 +46,111 @@ affs_count_free_blocks(struct super_block *s) free = 0; if (s->u.affs_sb.s_flags & SF_BM_VALID) { - for (i = 0; i < s->u.affs_sb.s_bm_count; i++) { - free += s->u.affs_sb.s_bitmap[i].bm_free; + for (i = 0; i < s->u.affs_sb.s_num_az; i++) { + free += s->u.affs_sb.s_alloc[i].az_free; } } return free; } void -affs_free_block(struct super_block *sb, LONG block) +affs_free_block(struct super_block *sb, int block) { int bmap; int bit; - ULONG blk; + int blk; + int zone_no; struct affs_bm_info *bm; pr_debug("AFFS: free_block(%d)\n",block); - blk = block - sb->u.affs_sb.s_reserved; - bmap = blk / (sb->s_blocksize * 8 - 32); - bit = blk % (sb->s_blocksize * 8 - 32); - bm = &sb->u.affs_sb.s_bitmap[bmap]; - if (bmap >= sb->u.affs_sb.s_bm_count || bit >= bm->bm_size) { + blk = block - sb->u.affs_sb.s_reserved; + bmap = blk / (sb->s_blocksize * 8 - 32); + bit = blk % (sb->s_blocksize * 8 - 32); + zone_no = (bmap << (sb->s_blocksize_bits - 7)) + bit / 1024; + bm = &sb->u.affs_sb.s_bitmap[bmap]; + if (bmap >= sb->u.affs_sb.s_bm_count) { printk("AFFS: free_block(): block %d outside partition.\n",block); return; } - blk = 0; + blk = 0; set_bit(bit & 31,&blk); lock_super(sb); + bm->bm_count++; + if (!bm->bm_bh) { + bm->bm_bh = affs_bread(sb->s_dev,bm->bm_key,sb->s_blocksize); + if (!bm->bm_bh) { + bm->bm_count--; + unlock_super(sb); + printk("AFFS: free_block(): Cannot read bitmap block %d\n",bm->bm_key); + return; + } + } if (set_bit(bit ^ BO_EXBITS,bm->bm_bh->b_data + 4)) printk("AFFS: free_block(): block %d is already free.\n",block); else { - bm->bm_free++; - ((ULONG *)bm->bm_bh->b_data)[0] = ntohl(htonl(((ULONG *)bm->bm_bh->b_data)[0]) - blk); + sb->u.affs_sb.s_alloc[zone_no].az_free++; + ((__u32 *)bm->bm_bh->b_data)[0] = ntohl(htonl(((__u32 *)bm->bm_bh->b_data)[0]) - blk); mark_buffer_dirty(bm->bm_bh,1); sb->s_dirt = 1; } + if (--bm->bm_count == 0) { + affs_brelse(bm->bm_bh); + bm->bm_bh = NULL; + } unlock_super(sb); } -static ULONG +static int affs_balloc(struct inode *inode, int zone_no) { - ULONG w; - ULONG *bm; + __u32 w; + __u32 *bm; int fb; int i; int fwb; - ULONG block; + int block; struct affs_zone *zone; + struct affs_alloc_zone *az; struct super_block *sb; sb = inode->i_sb; zone = &sb->u.affs_sb.s_zones[zone_no]; - if (!zone || !zone->z_bm || !zone->z_bm->bm_bh) - return 0; - + if (!zone->z_bm || !zone->z_bm->bm_bh) + return 0; + pr_debug("AFFS: balloc(inode=%lu,zone=%d)\n",inode->i_ino,zone_no); - bm = (ULONG *)zone->z_bm->bm_bh->b_data; + az = &sb->u.affs_sb.s_alloc[zone->z_az_no]; + bm = (__u32 *)zone->z_bm->bm_bh->b_data; repeat: - fb = (zone->z_bm->bm_size + 31) >> 5; - for (i = zone->z_start; i <= fb; i++) { + for (i = zone->z_start; i < zone->z_end; i++) { if (bm[i]) goto found; } - return 0; + return 0; found: fwb = zone->z_bm->bm_firstblk + (i - 1) * 32; lock_super(sb); zone->z_start = i; - w = htonl(bm[i]); - fb = find_first_one_bit(&w,32); + w = ~htonl(bm[i]); + fb = find_first_zero_bit(&w,32); if (fb > 31 || !clear_bit(fb ^ BO_EXBITS,&bm[i])) { unlock_super(sb); printk("AFFS: balloc(): empty block disappeared somehow\n"); goto repeat; } block = fwb + fb; - zone->z_bm->bm_free--; + az->az_free--; - /* prealloc as much as possible within this word, but not for headers */ + /* prealloc as much as possible within this word, but not in header zone */ if (zone_no) { while (inode->u.affs_i.i_pa_cnt < MAX_PREALLOC && ++fb < 32) { - fb = find_next_one_bit(&w,32,fb); + fb = find_next_zero_bit(&w,32,fb); if (fb > 31) break; if (!clear_bit(fb ^ BO_EXBITS,&bm[i])) { @@ -139,102 +160,129 @@ found: inode->u.affs_i.i_data[inode->u.affs_i.i_pa_last++] = fwb + fb; inode->u.affs_i.i_pa_last &= MAX_PREALLOC - 1; inode->u.affs_i.i_pa_cnt++; - zone->z_bm->bm_free--; + az->az_free--; } } - w -= htonl(bm[i]); + w = ~w - htonl(bm[i]); bm[0] = ntohl(htonl(bm[0]) + w); unlock_super(sb); mark_buffer_dirty(zone->z_bm->bm_bh,1); + zone->z_lru_time = jiffies; return block; } -static void -affs_find_new_zone(struct super_block *sb,struct affs_zone *z, int minfree, int start) +static int +affs_find_new_zone(struct super_block *sb, int zone_no) { struct affs_bm_info *bm; - int offs; - int zone; - int free; - int len; + struct affs_zone *zone; + struct affs_alloc_zone *az; + int bestfree; + int bestno; + int bestused; + int lusers; + int i; + int min; - pr_debug("AFFS: find_new_zone()\n"); + pr_debug("AFFS: find_new_zone(zone_no=%d)\n",zone_no); + bestfree = 0; + bestused = -1; + bestno = -1; + lusers = MAX_ZONES; + min = zone_no ? AFFS_DATA_MIN_FREE : AFFS_HDR_MIN_FREE; lock_super(sb); - - zone = start; - z->z_bm = NULL; - while (1) { - if (zone >= sb->u.affs_sb.s_num_zones) { - zone = 0; - continue; + zone = &sb->u.affs_sb.s_zones[zone_no]; + i = zone->z_az_no; + az = &sb->u.affs_sb.s_alloc[i]; + if (zone->z_bm && zone->z_bm->bm_count) { + if (--zone->z_bm->bm_count == 0) { + affs_brelse(zone->z_bm->bm_bh); + zone->z_bm->bm_bh = NULL; } + if (az->az_count) + az->az_count--; + else + printk("AFFS: find_new_zone(): az_count=0, but bm used\n"); - if (!set_bit(zone,sb->u.affs_sb.s_zonemap)) { - bm = &sb->u.affs_sb.s_bitmap[zone >> (sb->s_blocksize_bits - 8)]; - offs = zone * 256 & (sb->s_blocksize - 1); - len = bm->bm_size / 8 - offs; - if (len > 256) - len = 256; - offs += 4; - free = affs_count_free_bits(len,(char *)bm->bm_bh->b_data + offs); - if (free && (100 * free) / (len * 8) > minfree) { - z->z_bm = bm; - z->z_start = offs / 4; - z->z_ino = 0; - z->z_zone_no = zone; - pr_debug(" ++ found zone (%d) in bh %d at offset %d with %d free blocks\n", - zone,(zone >> (sb->s_blocksize_bits - 8)),offs,free); + } + while (1) { + if (i >= sb->u.affs_sb.s_num_az) + i = 0; + az = &sb->u.affs_sb.s_alloc[i]; + if (!az->az_count) { + if (az->az_free > min) { break; } - clear_bit(zone,sb->u.affs_sb.s_zonemap); + if (az->az_free > bestfree) { + bestfree = az->az_free; + bestno = i; + } + } else if (az->az_free && az->az_count < lusers) { + lusers = az->az_count; + bestused = i; } - - /* Skip to next possible zone */ - - pr_debug(" ++ Skipping to next zone\n"); - if (++zone == start) + if (++i == zone->z_az_no) { /* Seen all */ + if (bestno >= 0) { + i = bestno; + } else { + i = bestused; + } break; + } } + if (i < 0) { + /* Didn't find a single free block anywhere. */ + unlock_super(sb); + return 0; + } + az = &sb->u.affs_sb.s_alloc[i]; + az->az_count++; + bm = &sb->u.affs_sb.s_bitmap[i >> (sb->s_blocksize_bits - 7)]; + bm->bm_count++; + if (!bm->bm_bh) + bm->bm_bh = affs_bread(sb->s_dev,bm->bm_key,sb->s_blocksize); + if (!bm->bm_bh) { + bm->bm_count--; + az->az_count--; + unlock_super(sb); + printk("AFFS: find_new_zone(): Cannot read bitmap\n"); + return 0; + } + zone->z_bm = bm; + zone->z_start = (i & ((sb->s_blocksize / 128) - 1)) * 32 + 1; + zone->z_end = zone->z_start + az->az_size; + zone->z_az_no = i; + zone->z_lru_time = jiffies; + pr_debug(" ++ found zone (%d) in bm %d at lw offset %d with %d free blocks\n", + i,(i >> (sb->s_blocksize_bits - 7)),zone->z_start,az->az_free); unlock_super(sb); - return; + return az->az_free; } -LONG +int affs_new_header(struct inode *inode) { - struct affs_zone *zone; - LONG block; - struct super_block *sb; + int block; struct buffer_head *bh; - sb = inode->i_sb; - zone = &sb->u.affs_sb.s_zones[0]; - - /* We try up to 3 times to find a free block: - * If there is no more room in the current header zone, - * we try to get a new one and allocate the block there. - * If there is no zone with at least AFFS_HDR_MIN_FREE - * percent of free blocks, we try to find a zone with - * at least one free block. - */ + pr_debug("AFFS: new_header(ino=%lu)\n",inode->i_ino); if (!(block = affs_balloc(inode,0))) { - clear_bit(zone->z_zone_no,sb->u.affs_sb.s_zonemap); - affs_find_new_zone(sb,zone,AFFS_HDR_MIN_FREE,(sb->u.affs_sb.s_num_zones + 1) / 2); - if (!(block = affs_balloc(inode,0))) { - clear_bit(zone->z_zone_no,sb->u.affs_sb.s_zonemap); - affs_find_new_zone(sb,zone,0,(sb->u.affs_sb.s_num_zones + 1) / 2); - if (!(block = affs_balloc(inode,0))) - return 0; + while(affs_find_new_zone(inode->i_sb,0)) { + if ((block = affs_balloc(inode,0))) + goto init_block; + schedule(); } + return 0; } - if (!(bh = getblk(inode->i_dev,block,sb->s_blocksize))) { +init_block: + if (!(bh = getblk(inode->i_dev,block,AFFS_I2BSIZE(inode)))) { printk("AFFS: balloc(): cannot read block %d\n",block); return 0; } - memset(bh->b_data,0,sb->s_blocksize); + memset(bh->b_data,0,AFFS_I2BSIZE(inode)); mark_buffer_uptodate(bh,1); mark_buffer_dirty(bh,1); affs_brelse(bh); @@ -242,7 +290,7 @@ affs_new_header(struct inode *inode) return block; } -LONG +int affs_new_data(struct inode *inode) { int empty, old; @@ -251,7 +299,7 @@ affs_new_data(struct inode *inode) struct super_block *sb; struct buffer_head *bh; int i = 0; - LONG block; + int block; pr_debug("AFFS: new_data(ino=%lu)\n",inode->i_ino); @@ -265,7 +313,6 @@ affs_new_data(struct inode *inode) goto init_block; } unlock_super(sb); -repeat: oldest = jiffies; old = 0; empty = 0; @@ -287,19 +334,25 @@ repeat: i = empty; else if (old) i = old; - else + else { + inode->u.affs_i.i_zone = 0; return affs_new_header(inode); + } inode->u.affs_i.i_zone = i; zone->z_ino = inode->i_ino; found: zone = &sb->u.affs_sb.s_zones[i]; - if (!(block = affs_balloc(inode,i))) { /* Zone is full */ - clear_bit(zone->z_zone_no,sb->u.affs_sb.s_zonemap); - affs_find_new_zone(sb,zone,AFFS_DATA_MIN_FREE,sb->u.affs_sb.s_nextzone); - sb->u.affs_sb.s_nextzone = zone->z_zone_no + 1; - goto repeat; + if (!(block = affs_balloc(inode,i))) { /* No data zones left */ + while(affs_find_new_zone(sb,i)) { + if ((block = affs_balloc(inode,i))) + goto init_block; + schedule(); + } + inode->u.affs_i.i_zone = 0; + zone->z_ino = -1; + return 0; } init_block: @@ -318,15 +371,15 @@ init_block: void affs_make_zones(struct super_block *sb) { - int i, j; - - pr_debug("AFFS: make_zones(): num_zones=%d\n",sb->u.affs_sb.s_num_zones); + int i, mid; - j = (sb->u.affs_sb.s_num_zones + 1) / 2; + pr_debug("AFFS: make_zones(): num_zones=%d\n",sb->u.affs_sb.s_num_az); - affs_find_new_zone(sb,&sb->u.affs_sb.s_zones[0],AFFS_HDR_MIN_FREE,j); + mid = (sb->u.affs_sb.s_num_az + 1) / 2; + sb->u.affs_sb.s_zones[0].z_az_no = mid; + affs_find_new_zone(sb,0); for (i = 1; i < MAX_ZONES; i++) { - affs_find_new_zone(sb,&sb->u.affs_sb.s_zones[i],AFFS_DATA_MIN_FREE,j); - j = sb->u.affs_sb.s_zones[i].z_zone_no + 1; + sb->u.affs_sb.s_zones[i].z_az_no = mid; + affs_find_new_zone(sb,i); } } diff --git a/fs/affs/dir.c b/fs/affs/dir.c index cf443bf8b5bb..ad6a642f8e66 100644 --- a/fs/affs/dir.c +++ b/fs/affs/dir.c @@ -1,7 +1,7 @@ /* * linux/fs/affs/dir.c * - * (c) 1996 Hans-Joachim Widmaier - rewritten + * (c) 1996 Hans-Joachim Widmaier - Rewritten * * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. * @@ -58,7 +58,7 @@ struct inode_operations affs_dir_inode_operations = { NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ - affs_dir_truncate, /* truncate */ + NULL, /* truncate */ NULL /* permissions */ }; @@ -72,11 +72,11 @@ static int affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t filldir) { int j, namelen; - LONG i; - ULONG hash_pos; - ULONG chain_pos; + int i; + int hash_pos; + int chain_pos; unsigned long ino; - unsigned long old; + unsigned long old; int stored; char *name; struct buffer_head *dir_bh; @@ -142,9 +142,9 @@ affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t fil * we can jump directly to where we left off. */ if (filp->private_data && filp->f_version == dir->i_version) { - i = (ULONG)filp->private_data; + i = (int)filp->private_data; j = 0; - pr_debug("AFFS: readdir() left off=%lu\n",i); + pr_debug("AFFS: readdir() left off=%d\n",i); } filp->f_version = dir->i_version; pr_debug("AFFS: hash_pos=%lu chain_pos=%lu\n", hash_pos, chain_pos); @@ -163,7 +163,8 @@ affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t fil } if (fh_bh) { namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name); - pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%lu\n",namelen,name,ino,i); + pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%lu\n", + namelen,name,ino,i); filp->private_data = (void *)ino; if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0) goto readdir_done; @@ -188,9 +189,3 @@ readdir_done: pr_debug("AFFS: readdir()=%d\n",stored); return stored; } - -void -affs_dir_truncate(struct inode *inode) -{ - printk("AFFS: dir_truncate()\n"); -} diff --git a/fs/affs/file.c b/fs/affs/file.c index 4b872ec5bd68..6cfbbf7245f1 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -1,7 +1,7 @@ /* * linux/fs/affs/file.c * - * (c) 1996 Hans-Joachim Widmaier - rewritten + * (c) 1996 Hans-Joachim Widmaier - Rewritten * * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. * @@ -104,11 +104,11 @@ struct inode_operations affs_file_inode_operations_ofs = { }; int -affs_bmap(struct inode *inode, LONG block) +affs_bmap(struct inode *inode, int block) { struct buffer_head *bh; - LONG ext, key; - LONG ptype, stype; + int ext, key; + int ptype, stype; pr_debug("AFFS: bmap(%lu,%d)\n",inode->i_ino,block); @@ -155,13 +155,13 @@ affs_bmap(struct inode *inode, LONG block) } struct buffer_head * -affs_getblock(struct inode *inode, LONG block) +affs_getblock(struct inode *inode, int block) { struct buffer_head *bh; struct buffer_head *ebh; - LONG key; - LONG ext; - LONG cnt, j, pt; + int key; + int ext; + int cnt, j, pt; pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block); @@ -258,28 +258,28 @@ affs_getblock(struct inode *inode, LONG block) affs_brelse(bh); if (!key) return NULL; - + return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)); } struct buffer_head * -affs_getblock_ofs(struct inode *inode, LONG block, LONG *blk_key) +affs_getblock_ofs(struct inode *inode, int block, int *blk_key) { struct buffer_head *bh; struct buffer_head *pbh; struct buffer_head *ebh; - LONG key; - LONG ext; - LONG cnt, j, pt; + int key; + int ext; + int cnt, j, pt; - pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block); + pr_debug("AFFS: getblock_ofs(%lu,%d)\n",inode->i_ino,block); if (block < 0) return NULL; key = inode->i_ino; pt = T_SHORT; - ext = block / (AFFS_I2HSIZE(inode) - 24); + ext = block / AFFS_I2HSIZE(inode); if (ext) { if (ext > inode->u.affs_i.i_max_ext) ext = inode->u.affs_i.i_max_ext; @@ -305,7 +305,11 @@ affs_getblock_ofs(struct inode *inode, LONG block, LONG *blk_key) j = htonl(((struct file_front *)bh->b_data)->block_count); while (j < AFFS_I2HSIZE(inode) && j <= block) { if (!pbh && inode->u.affs_i.i_lastblock >= 0) { - pbh = affs_getblock_ofs(inode,inode->u.affs_i.i_lastblock,&key); + if (j > 0) + pbh = affs_bread(inode->i_dev,ntohl(AFFS_BLOCK(bh->b_data,inode,j - 1)), + AFFS_I2BSIZE(inode)); + else + pbh = affs_getblock_ofs(inode,inode->u.affs_i.i_lastblock,&key); if (!pbh) { printk("AFFS: getblock(): cannot get last block in file\n"); break; @@ -335,12 +339,14 @@ affs_getblock_ofs(struct inode *inode, LONG block, LONG *blk_key) DATA_FRONT(ebh)->primary_type = ntohl(T_DATA); DATA_FRONT(ebh)->header_key = ntohl(inode->i_ino); DATA_FRONT(ebh)->sequence_number = ntohl(inode->u.affs_i.i_lastblock + 1); - DATA_FRONT(pbh)->data_size = ntohl(AFFS_I2HSIZE(inode) - 24); - DATA_FRONT(pbh)->next_data = ntohl(key); - affs_fix_checksum(AFFS_I2HSIZE(inode),pbh->b_data,5); - mark_buffer_dirty(pbh,0); - mark_buffer_dirty(ebh,0); - affs_brelse(pbh); + if (pbh) { + DATA_FRONT(pbh)->data_size = ntohl(AFFS_I2BSIZE(inode) - 24); + DATA_FRONT(pbh)->next_data = ntohl(key); + affs_fix_checksum(AFFS_I2BSIZE(inode),pbh->b_data,5); + mark_buffer_dirty(pbh,0); + mark_buffer_dirty(ebh,0); + affs_brelse(pbh); + } pbh = ebh; j++; } @@ -433,10 +439,10 @@ affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, int count) left = MIN (inode->i_size - filp->f_pos,count - (buf - start)); if (!left) break; - sector = affs_bmap(inode,(ULONG)filp->f_pos / blocksize); + sector = affs_bmap(inode,(__u32)filp->f_pos / blocksize); if (!sector) break; - offset = (ULONG)filp->f_pos % blocksize; + offset = (__u32)filp->f_pos % blocksize; bh = affs_bread(inode->i_dev,sector,AFFS_I2BSIZE(inode)); if (!bh) break; @@ -537,6 +543,7 @@ affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int off_t pos; int written; int c; + int key; int blocksize; struct buffer_head *bh; struct inode *ino; @@ -546,7 +553,7 @@ affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int (unsigned long)filp->f_pos,count); if (!inode) { - printk("AFFS: file_write(): inode=NULL\n"); + printk("AFFS: file_write_ofs(): inode=NULL\n"); return -EINVAL; } ino = NULL; @@ -560,7 +567,7 @@ affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int inode = ino; } if (!S_ISREG(inode->i_mode)) { - printk("AFFS: file_write(): mode=%07o\n",inode->i_mode); + printk("AFFS: file_write_ofs(): mode=%07o\n",inode->i_mode); iput(inode); return -EINVAL; } @@ -573,7 +580,7 @@ affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int blocksize = AFFS_I2BSIZE(inode) - 24; written = 0; while (written < count) { - bh = affs_getblock(inode,pos / blocksize); + bh = affs_getblock_ofs(inode,pos / blocksize,&key); if (!bh) { if (!written) written = -ENOSPC; @@ -620,12 +627,13 @@ affs_truncate(struct inode *inode) struct buffer_head *bh; struct buffer_head *ebh; struct inode *ino; - LONG first; - LONG block; - LONG key; - LONG *keyp; - LONG ekey; - LONG ptype, stype; + struct affs_zone *zone; + int first; + int block; + int key; + int *keyp; + int ekey; + int ptype, stype; int freethis; int blocksize; int rem; @@ -646,7 +654,24 @@ affs_truncate(struct inode *inode) blocksize = AFFS_I2BSIZE(inode) - ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) ? 24 : 0); first = (inode->i_size + blocksize - 1) / blocksize; if (inode->u.affs_i.i_lastblock < first - 1) { - bh = affs_getblock(inode,first - 1); + if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) + bh = affs_getblock_ofs(inode,first - 1,&ekey); + else + bh = affs_getblock(inode,first - 1); + + while (inode->u.affs_i.i_pa_cnt) { /* Free any preallocated blocks */ + affs_free_block(inode->i_sb, + inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++]); + inode->u.affs_i.i_pa_next &= MAX_PREALLOC - 1; + inode->u.affs_i.i_pa_cnt--; + } + if (inode->u.affs_i.i_zone) { + lock_super(inode->i_sb); + zone = &inode->i_sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone]; + if (zone->z_ino == inode->i_ino) + zone->z_ino = 0; + unlock_super(inode->i_sb); + } if (!bh) { printk("AFFS: truncate(): Cannot extend file\n"); inode->i_size = blocksize * (inode->u.affs_i.i_lastblock + 1); diff --git a/fs/affs/inode.c b/fs/affs/inode.c index cba69f8ddf74..a1f3228f6071 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -1,7 +1,7 @@ /* * linux/fs/affs/inode.c * - * (c) 1996 Hans-Joachim Widmaier - rewritten + * (c) 1996 Hans-Joachim Widmaier - Rewritten * * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. * @@ -25,12 +25,15 @@ #include #include #include +#include #include #include extern int *blk_size[]; extern struct timezone sys_tz; +#define MIN(a,b) (((a)<(b))?(a):(b)) + void affs_put_super(struct super_block *sb) { @@ -39,15 +42,13 @@ affs_put_super(struct super_block *sb) pr_debug("affs_put_super()\n"); lock_super(sb); - if (!(sb->s_flags & MS_RDONLY)) { - for (i = 0; i < sb->u.affs_sb.s_bm_count; i++) - affs_brelse(sb->u.affs_sb.s_bitmap[i].bm_bh); - ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(1); - secs_to_datestamp(CURRENT_TIME, - &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered); - affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5); - mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1); - } + for (i = 0; i < sb->u.affs_sb.s_bm_count; i++) + affs_brelse(sb->u.affs_sb.s_bitmap[i].bm_bh); + ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(1); + secs_to_datestamp(CURRENT_TIME,&ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered); + affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5); + mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1); + if (sb->u.affs_sb.s_flags & SF_PREFIX) kfree(sb->u.affs_sb.s_prefix); kfree(sb->u.affs_sb.s_bitmap); @@ -62,15 +63,24 @@ affs_put_super(struct super_block *sb) static void affs_write_super(struct super_block *sb) { - int i, clean = 2; + int i, clean = 2; + if ((sb->u.affs_sb.s_flags & SF_USE_MP) && !sb->u.affs_sb.s_uid && sb->s_covered) { + sb->s_mounted->i_uid = sb->u.affs_sb.s_uid = sb->s_covered->i_uid; + sb->s_mounted->i_gid = sb->u.affs_sb.s_gid = sb->s_covered->i_gid; + sb->u.affs_sb.s_flags &= ~SF_USE_MP; + } if (!(sb->s_flags & MS_RDONLY)) { + lock_super(sb); for (i = 0, clean = 1; i < sb->u.affs_sb.s_bm_count; i++) { - if (buffer_dirty(sb->u.affs_sb.s_bitmap[i].bm_bh)) { - clean = 0; - break; + if (sb->u.affs_sb.s_bitmap[i].bm_bh) { + if (buffer_dirty(sb->u.affs_sb.s_bitmap[i].bm_bh)) { + clean = 0; + break; + } } } + unlock_super(sb); ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(clean); secs_to_datestamp(CURRENT_TIME, &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered); @@ -108,7 +118,6 @@ affs_parent_ino(struct inode *dir) return dir->u.affs_i.i_parent; } - static int parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, int *root, int *blocksize, char **prefix, char *volume, unsigned long *mount_opts) @@ -140,6 +149,13 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, i } *mount_opts |= SF_IMMUTABLE; } + if (!strcmp(this_char,"usemp")) { + if (value) { + printk("AFFS: option usemp does not take an argument\n"); + return 0; + } + *mount_opts |= SF_USE_MP; + } else if (!strcmp(this_char,"verbose")) { if (value) { printk("AFFS: option verbose does not take an argument\n"); @@ -251,6 +267,10 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, i return 1; } +/* This function definately needs to be split up. Some fine day I'll + * hopefully have the guts to do so. Until then: sorry for the mess. + */ + struct super_block * affs_read_super(struct super_block *s,void *data, int silent) { @@ -259,26 +279,26 @@ affs_read_super(struct super_block *s,void *data, int silent) kdev_t dev = s->s_dev; int root_block; int size; - ULONG chksum; - ULONG *bm; - LONG ptype, stype; - int mapidx = 0; + __u32 chksum; + __u32 *bm; + int ptype, stype; + int mapidx; int num_bm; - int i; + int i, j; int key; int blocksize; uid_t uid; gid_t gid; - int mode, reserved; - int zm_size; + int reserved; + int az_no; unsigned long mount_flags; - ULONG offset; + unsigned long offset; - pr_debug("affs_read_super(%s)\n",(const char *)data); + pr_debug("affs_read_super(%s)\n",data ? (const char *)data : "no options"); MOD_INC_USE_COUNT; - if (!parse_options(data,&uid,&gid,&mode,&reserved,&root_block, + if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block, &blocksize,&s->u.affs_sb.s_prefix,s->u.affs_sb.s_volume,&mount_flags)) { s->s_dev = 0; printk("AFFS: error parsing options.\n"); @@ -292,13 +312,15 @@ affs_read_super(struct super_block *s,void *data, int silent) * blocks, we will have to change it. */ - size = 2 * blk_size[MAJOR(dev)][MINOR(dev)]; - s->u.affs_sb.s_bitmap = NULL; - s->u.affs_sb.s_root_bh = NULL; - s->u.affs_sb.s_flags = mount_flags; - s->u.affs_sb.s_mode = mode; - s->u.affs_sb.s_uid = uid; - s->u.affs_sb.s_gid = gid; + size = blksize_size[MAJOR(dev)][MINOR(dev)]; + size = (size ? size : BLOCK_SIZE) / 512 * blk_size[MAJOR(dev)][MINOR(dev)]; + + s->u.affs_sb.s_bitmap = NULL; + s->u.affs_sb.s_root_bh = NULL; + s->u.affs_sb.s_flags = mount_flags; + s->u.affs_sb.s_mode = i; + s->u.affs_sb.s_uid = uid; + s->u.affs_sb.s_gid = gid; if (size == 0) { s->s_dev = 0; @@ -320,15 +342,12 @@ affs_read_super(struct super_block *s,void *data, int silent) num_bm = 4096; } for (blocksize = chksum; blocksize <= num_bm; blocksize <<= 1, size >>= 1) { - if (root_block < 0){ - if (MAJOR(dev) == FLOPPY_MAJOR) - s->u.affs_sb.s_root_block = size/4; - else + if (root_block < 0) s->u.affs_sb.s_root_block = (reserved + size - 1) / 2; - }else + else s->u.affs_sb.s_root_block = root_block; pr_debug("Trying bs=%d bytes, root at %d, size=%d blocks (%d reserved)\n", - blocksize,s->u.affs_sb.s_root_block,size,reserved); + blocksize,s->u.affs_sb.s_root_block,size,reserved); set_blocksize(dev,blocksize); bh = affs_bread(dev,s->u.affs_sb.s_root_block,blocksize); if (!bh) { @@ -360,7 +379,7 @@ affs_read_super(struct super_block *s,void *data, int silent) /* Find out which kind of FS we have */ bb = affs_bread(dev,0,s->s_blocksize); if (bb) { - chksum = htonl(*(ULONG *)bb->b_data); + chksum = htonl(*(__u32 *)bb->b_data); switch (chksum) { case MUFS_FS: case MUFS_INTLFFS: @@ -422,20 +441,28 @@ affs_read_super(struct super_block *s,void *data, int silent) goto out; } - /* Allocate space for bitmap pointers and read the bitmap */ + /* Allocate space for bitmaps, zones and others */ - size = s->u.affs_sb.s_partition_size - reserved; - num_bm = (size + s->s_blocksize * 8 - 32 - 1) / (s->s_blocksize * 8 - 32); - zm_size = (num_bm * (1 << (s->s_blocksize_bits - 8)) + 7) / 8; - ptype = num_bm * sizeof(struct affs_bm_info) + zm_size + - MAX_ZONES * sizeof(struct affs_zone); + size = s->u.affs_sb.s_partition_size - reserved; + num_bm = (size + s->s_blocksize * 8 - 32 - 1) / (s->s_blocksize * 8 - 32); + az_no = (size + AFFS_ZONE_SIZE - 1) / (AFFS_ZONE_SIZE - 32); + ptype = num_bm * sizeof(struct affs_bm_info) + + az_no * sizeof(struct affs_alloc_zone) + + MAX_ZONES * sizeof(struct affs_zone); + pr_debug("num_bm=%d, az_no=%d, sum=%d\n",num_bm,az_no,ptype); if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype,GFP_KERNEL))) { - printk("AFFS: Can't get memory for bitmap info.\n"); + printk("AFFS: Not enough memory.\n"); goto out; } memset(s->u.affs_sb.s_bitmap,0,ptype); - if( (ULONG)((UBYTE *)bh->b_data + s->s_blocksize - 200) == 0 ) { + s->u.affs_sb.s_zones = (struct affs_zone *)&s->u.affs_sb.s_bitmap[num_bm]; + s->u.affs_sb.s_alloc = (struct affs_alloc_zone *)&s->u.affs_sb.s_zones[MAX_ZONES]; + s->u.affs_sb.s_num_az = az_no; + + mapidx = 0; + + if (ROOT_END_S(bh->b_data,s)->bm_flag == 0) { if (!(s->s_flags & MS_RDONLY)) { printk("AFFS: Bitmap invalid - mounting %s read only.\n",kdevname(dev)); s->s_flags |= MS_RDONLY; @@ -445,14 +472,17 @@ affs_read_super(struct super_block *s,void *data, int silent) goto nobitmap; } - pr_debug("AFFS: %d bitmap blocks\n",num_bm); + /* The following section is ugly, I know. Especially because of the + * reuse of some variables that are not named properly. + */ key = root_block; ptype = s->s_blocksize / 4 - 49; stype = ptype + 25; offset = s->u.affs_sb.s_reserved; + az_no = 0; while (bh) { - bm = (ULONG *)bh->b_data; + bm = (__u32 *)bh->b_data; for (i = ptype; i < stype && bm[i]; i++, mapidx++) { if (mapidx >= num_bm) { printk("AFFS: Not enough bitmap space!?\n"); @@ -460,21 +490,22 @@ affs_read_super(struct super_block *s,void *data, int silent) } bb = affs_bread(s->s_dev,htonl(bm[i]),s->s_blocksize); if (bb) { - if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) /*&& - !(s->s_flags & MS_RDONLY)*/) { + if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) && + !(s->s_flags & MS_RDONLY)) { printk("AFFS: Bitmap (%d,key=%lu) invalid - " "mounting %s read only.\n",mapidx,htonl(bm[i]), kdevname(dev)); s->s_flags |= MS_RDONLY; } + /* Mark unused bits in the last word as allocated */ if (size <= s->s_blocksize * 8 - 32) { /* last bitmap */ ptype = size / 32 + 1; /* word number */ key = size & 0x1F; /* used bits */ if (key) { chksum = ntohl(0x7FFFFFFF >> (31 - key)); - ((ULONG *)bb->b_data)[ptype] &= chksum; + ((__u32 *)bb->b_data)[ptype] &= chksum; affs_fix_checksum(s->s_blocksize,bb->b_data,0); - /* no need to mark buffer as dirty */ + mark_buffer_dirty(bb,1); } ptype = (size + 31) & ~0x1F; size = 0; @@ -485,11 +516,19 @@ affs_read_super(struct super_block *s,void *data, int silent) size -= ptype; } s->u.affs_sb.s_bitmap[mapidx].bm_firstblk = offset; - s->u.affs_sb.s_bitmap[mapidx].bm_size = ptype; - s->u.affs_sb.s_bitmap[mapidx].bm_bh = bb; - s->u.affs_sb.s_bitmap[mapidx].bm_free = - affs_count_free_bits(ptype / 8,bb->b_data + 4); + s->u.affs_sb.s_bitmap[mapidx].bm_bh = NULL; + s->u.affs_sb.s_bitmap[mapidx].bm_key = htonl(bm[i]); + s->u.affs_sb.s_bitmap[mapidx].bm_count = 0; offset += ptype; + + for (j = 0; ptype > 0; j++, az_no++, ptype -= key) { + key = MIN(ptype,AFFS_ZONE_SIZE); /* size in bits */ + s->u.affs_sb.s_alloc[az_no].az_size = key / 32; + s->u.affs_sb.s_alloc[az_no].az_free = + affs_count_free_bits(key / 8,bb->b_data + + j * (AFFS_ZONE_SIZE / 8) + 4); + } + affs_brelse(bb); } else { printk("AFFS: Can't read bitmap.\n"); goto out; @@ -511,18 +550,15 @@ affs_read_super(struct super_block *s,void *data, int silent) printk("AFFS: Got only %d bitmap blocks, expected %d\n",mapidx,num_bm); goto out; } - s->u.affs_sb.s_num_zones = ((num_bm - 1) << (s->s_blocksize_bits - 8)) + - (s->u.affs_sb.s_bitmap[num_bm - 1].bm_size + 2047) / 2048; nobitmap: s->u.affs_sb.s_bm_count = mapidx; - s->u.affs_sb.s_zones = (struct affs_zone *)&s->u.affs_sb.s_bitmap[num_bm]; - s->u.affs_sb.s_zonemap = (char *)&s->u.affs_sb.s_zones[MAX_ZONES]; /* set up enough so that it can read an inode */ s->s_dev = dev; s->s_op = &affs_sops; s->s_mounted = iget(s,root_block); + s->s_dirt = 1; unlock_super(s); if (!(s->s_mounted)) { @@ -532,7 +568,7 @@ nobitmap: return NULL; } - /* If the fs is mounted r/w, create data zones, else free bitmaps. */ + /* create data zones if the fs is mounted r/w */ if (!(s->s_flags & MS_RDONLY)) { ROOT_END(s->u.affs_sb.s_root_bh->b_data,s->s_mounted)->bm_flag = 0; @@ -541,13 +577,7 @@ nobitmap: affs_fix_checksum(s->s_blocksize,s->u.affs_sb.s_root_bh->b_data,5); mark_buffer_dirty(s->u.affs_sb.s_root_bh,1); affs_make_zones(s); - } else { - for (i = 0; i < s->u.affs_sb.s_bm_count; i++) { - affs_brelse(s->u.affs_sb.s_bitmap[i].bm_bh); - s->u.affs_sb.s_bitmap[i].bm_bh = NULL; - } } - pr_debug("AFFS: s_flags=%lX\n",s->s_flags); return s; @@ -555,11 +585,8 @@ nobitmap: out: /* Kick out for various error conditions */ affs_brelse (bh); affs_brelse(s->u.affs_sb.s_root_bh); - if (s->u.affs_sb.s_bitmap) { - for (i = 0; i < mapidx; i++) - affs_brelse(s->u.affs_sb.s_bitmap[i].bm_bh); + if (s->u.affs_sb.s_bitmap) kfree(s->u.affs_sb.s_bitmap); - } s->s_dev = 0; unlock_super(s); MOD_DEC_USE_COUNT; @@ -569,7 +596,7 @@ nobitmap: void affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) { - ULONG free; + int free; struct statfs tmp; pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",sb->u.affs_sb.s_partition_size, @@ -592,9 +619,9 @@ affs_read_inode(struct inode *inode) struct buffer_head *bh, *lbh; struct file_front *file_front; struct file_end *file_end; - LONG block; - ULONG prot; - LONG ptype, stype; + int block; + unsigned long prot; + int ptype, stype; unsigned short id; pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino); @@ -817,7 +844,7 @@ affs_new_inode(const struct inode *dir) { struct inode *inode; struct super_block *sb; - ULONG block; + int block; if (!dir || !(inode = get_empty_inode())) return NULL; @@ -863,15 +890,15 @@ affs_new_inode(const struct inode *dir) int affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode, - const char *name, int len, LONG type) + const char *name, int len, int type) { struct buffer_head *dir_bh; struct buffer_head *inode_bh; struct buffer_head *link_bh; - ULONG hash; + int hash; - pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%ld\n",dir->i_ino,inode->i_ino, - len,name,type); + pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%d\n",dir->i_ino,inode->i_ino, + len,name,type); dir_bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir)); inode_bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); diff --git a/fs/affs/namei.c b/fs/affs/namei.c index b5bd1510cfe7..f9f40b36286b 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -1,7 +1,7 @@ /* * linux/fs/affs/namei.c * - * (c) 1996 Hans-Joachim Widmaier - rewritten + * (c) 1996 Hans-Joachim Widmaier - Rewritten * * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. * @@ -10,12 +10,12 @@ #include #include -#include #include #include #include #include #include +#include #include #include @@ -100,7 +100,7 @@ affs_find_entry(struct inode *dir, const char *name, int namelen, { struct buffer_head *bh; int intl; - ULONG key; + int key; pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name); @@ -137,7 +137,6 @@ affs_find_entry(struct inode *dir, const char *name, int namelen, break; key = htonl(FILE_END(bh->b_data,dir)->hash_chain); } - pr_debug("%lu\n",key); *ino = key; return bh; } @@ -379,7 +378,6 @@ affs_symlink(struct inode *dir, const char *name, int len, const char *symname) char c, lc; pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname); - printk("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname); maxlen = 4 * AFFS_I2HSIZE(dir) - 1; inode = affs_new_inode(dir); @@ -548,7 +546,7 @@ affs_rename(struct inode *old_dir, const char *old_name, int old_len, int retval; pr_debug("AFFS: rename(old=%lu,\"%*s\" to new=%lu,\"%*s\")\n",old_dir->i_ino,old_len,old_name, - new_dir->i_ino,new_len,new_name); + new_dir->i_ino,new_len,new_name); if (new_len > 30) new_len = 30; @@ -607,7 +605,7 @@ start_up: if (affs_parent_ino(old_inode) != old_dir->i_ino) goto end_rename; } - /* Unlink destination if existant */ + /* Unlink destination if existent */ if (new_inode) { if ((retval = affs_fix_hash_pred(new_dir,affs_hash_name(new_name,new_len, AFFS_I2FSTYPE(new_dir),AFFS_I2HSIZE(new_dir)) + 6, @@ -652,8 +650,8 @@ end_rename: int affs_fixup(struct buffer_head *bh, struct inode *inode) { - ULONG key, link_key; - LONG type; + int key, link_key; + int type; struct buffer_head *nbh; struct inode *ofinode; diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c index 2f0e98bcaeeb..fe790ef5c04d 100644 --- a/fs/affs/symlink.c +++ b/fs/affs/symlink.c @@ -1,7 +1,7 @@ /* * linux/fs/affs/symlink.c * - * 1995 Hans-Joachim Widmaier - modified for affs. + * 1995 Hans-Joachim Widmaier - Modified for affs. * * Copyright (C) 1991, 1992 Linus Torvalds * diff --git a/fs/buffer.c b/fs/buffer.c index a6000753719c..a8952c87c638 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1270,6 +1270,8 @@ void unlock_buffer(struct buffer_head * bh) deemed complete once all buffers have been visited (b_count==0) and are now unlocked. */ bh->b_count--; + if (!test_bit(BH_Uptodate, &bh->b_state)) + set_bit(PG_error, &page->flags); for (tmp = bh; tmp=tmp->b_this_page, tmp!=bh; ) { if (test_bit(BH_Lock, &tmp->b_state) || tmp->b_count) return; diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index aef0846ba0c1..9f267e69dced 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -367,7 +367,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de, } /* - * If this component record isnt continued, then append a '/'. + * If this component record isn't continued, then append a '/'. */ if( (!rootflag) && ((oldslp->flags & 1) == 0) ) inode->i_size += 1; @@ -529,7 +529,7 @@ char * get_rock_ridge_symlink(struct inode * inode) } /* - * If this component record isnt continued, then append a '/'. + * If this component record isn't continued, then append a '/'. */ if( (!rootflag) && ((oldslp->flags & 1) == 0) ) strcat(rpnt,"/"); diff --git a/include/asm-alpha/unaligned.h b/include/asm-alpha/unaligned.h index 071477496646..69a2d54b2707 100644 --- a/include/asm-alpha/unaligned.h +++ b/include/asm-alpha/unaligned.h @@ -1,10 +1,26 @@ #ifndef __ALPHA_UNALIGNED_H #define __ALPHA_UNALIGNED_H +/* + * The main single-value unaligned transfer routines. + */ +#define get_unaligned(ptr) \ + ((__typeof__(*(ptr)))__get_unaligned((ptr), sizeof(*(ptr)))) +#define put_unaligned(x,ptr) \ + __put_unaligned((unsigned long)(x), (ptr), sizeof(*(ptr))) + +/* + * This is a silly but good way to make sure that + * the get/put functions are indeed always optimized, + * and that we use the correct sizes. + */ +extern void bad_unaligned_access_length(void); + /* - * inline functions to do unaligned accesses.. See entUna in traps.c + * Elemental unaligned loads */ -extern inline unsigned long ldq_u(unsigned long * r11) + +extern inline unsigned long __uldq(const unsigned long * r11) { unsigned long r1,r2; __asm__("ldq_u %0,%3\n\t" @@ -15,11 +31,11 @@ extern inline unsigned long ldq_u(unsigned long * r11) :"=&r" (r1), "=&r" (r2) :"r" (r11), "m" (*r11), - "m" (*(unsigned long *)(7+(char *) r11))); + "m" (*(const unsigned long *)(7+(char *) r11))); return r1; } -extern inline unsigned long ldl_u(unsigned int * r11) +extern inline unsigned long __uldl(const unsigned int * r11) { unsigned long r1,r2; __asm__("ldq_u %0,%3\n\t" @@ -30,11 +46,11 @@ extern inline unsigned long ldl_u(unsigned int * r11) :"=&r" (r1), "=&r" (r2) :"r" (r11), "m" (*r11), - "m" (*(unsigned long *)(3+(char *) r11))); + "m" (*(const unsigned long *)(3+(char *) r11))); return r1; } -extern inline unsigned long ldw_u(unsigned short * r11) +extern inline unsigned long __uldw(const unsigned short * r11) { unsigned long r1,r2; __asm__("ldq_u %0,%3\n\t" @@ -45,11 +61,15 @@ extern inline unsigned long ldw_u(unsigned short * r11) :"=&r" (r1), "=&r" (r2) :"r" (r11), "m" (*r11), - "m" (*(unsigned long *)(1+(char *) r11))); + "m" (*(const unsigned long *)(1+(char *) r11))); return r1; } -extern inline void stq_u(unsigned long r5, unsigned long * r11) +/* + * Elemental unaligned stores + */ + +extern inline void __ustq(unsigned long r5, unsigned long * r11) { unsigned long r1,r2,r3,r4; @@ -69,7 +89,7 @@ extern inline void stq_u(unsigned long r5, unsigned long * r11) :"r" (r5), "r" (r11)); } -extern inline void stl_u(unsigned long r5, unsigned int * r11) +extern inline void __ustl(unsigned long r5, unsigned int * r11) { unsigned long r1,r2,r3,r4; @@ -89,7 +109,7 @@ extern inline void stl_u(unsigned long r5, unsigned int * r11) :"r" (r5), "r" (r11)); } -extern inline void stw_u(unsigned long r5, unsigned short * r11) +extern inline void __ustw(unsigned long r5, unsigned short * r11) { unsigned long r1,r2,r3,r4; @@ -109,4 +129,46 @@ extern inline void stw_u(unsigned long r5, unsigned short * r11) :"r" (r5), "r" (r11)); } +extern inline unsigned long __get_unaligned(const void *ptr, size_t size) +{ + unsigned long val; + switch (size) { + case 1: + val = *(const unsigned char *)ptr; + break; + case 2: + val = __uldw((const unsigned short *)ptr); + break; + case 4: + val = __uldl((const unsigned int *)ptr); + break; + case 8: + val = __uldq((const unsigned long *)ptr); + break; + default: + bad_unaligned_access_length(); + } + return val; +} + +extern inline void __put_unaligned(unsigned long val, void *ptr, size_t size) +{ + switch (size) { + case 1: + *(unsigned char *)ptr = (val); + break; + case 2: + __ustw(val, (unsigned short *)ptr); + break; + case 4: + __ustl(val, (unsigned int *)ptr); + break; + case 8: + __ustq(val, (unsigned long *)ptr); + break; + default: + bad_unaligned_access_length(); + } +} + #endif diff --git a/include/asm-generic/unaligned.h b/include/asm-generic/unaligned.h new file mode 100644 index 000000000000..57b14024ca57 --- /dev/null +++ b/include/asm-generic/unaligned.h @@ -0,0 +1,20 @@ +#ifndef _ASM_GENERIC_UNALIGNED_H_ +#define _ASM_GENERIC_UNALIGNED_H_ + +/* + * For the benefit of those who are trying to port Linux to another + * architecture, here are some C-language equivalents. + */ + +#include + + +#define get_unaligned(ptr) \ + ({ __typeof__(*(ptr)) __tmp; memcpy(&__tmp, (ptr), sizeof(*(ptr))); __tmp; }) + +#define put_unaligned(val, ptr) \ + ({ __typeof__(*(ptr)) __tmp = (val); \ + memcpy((ptr), &__tmp, sizeof(*(ptr))); \ + (void)0; }) + +#endif /* _ASM_GENERIC_UNALIGNED_H */ diff --git a/include/asm-i386/unaligned.h b/include/asm-i386/unaligned.h new file mode 100644 index 000000000000..282ce190efb3 --- /dev/null +++ b/include/asm-i386/unaligned.h @@ -0,0 +1,16 @@ +#ifndef __I386_UNALIGNED_H +#define __I386_UNALIGNED_H + +/* + * The i386 can do unaligned accesses itself. + * + * The strange macros are there to make sure these can't + * be misused in a way that makes them not work on other + * architectures where unaligned accesses aren't as simple. + */ + +#define get_unaligned(ptr) (*(ptr)) + +#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) )) + +#endif diff --git a/include/linux/affs_fs.h b/include/linux/affs_fs.h index 15c4c11227ac..acc6f00940e8 100644 --- a/include/linux/affs_fs.h +++ b/include/linux/affs_fs.h @@ -5,7 +5,6 @@ */ #include -#include #define AFFS_SUPER_MAGIC 0xadff @@ -21,29 +20,37 @@ /* Get the fs type given an inode */ #define AFFS_I2FSTYPE(inode) ((inode)->i_sb->u.affs_sb.s_flags & SF_INTL) +struct DateStamp +{ + __u32 ds_Days; + __u32 ds_Minute; + __u32 ds_Tick; +}; + + /* --- Prototypes ----------------------------------------------------------------------------- */ /* amigaffs.c */ extern int affs_get_key_entry(int bsize, void *data, int entry_pos); -extern int affs_find_next_hash_entry(int bsize, void *dir_data, __u32 *hash_pos); +extern int affs_find_next_hash_entry(int bsize, void *dir_data, int *hash_pos); extern int affs_get_file_name(int bsize, void *fh_data, char **name); -extern __u32 affs_checksum_block(int bsize, void *data, __s32 *ptype, __s32 *stype); +extern unsigned int affs_checksum_block(int bsize, void *data, int *ptype, int *stype); extern void affs_fix_checksum(int bsize, void *data, int cspos); extern void secs_to_datestamp(int secs, struct DateStamp *ds); -extern int prot_to_mode(__u32 prot); -extern __u32 mode_to_prot(int mode); +extern int prot_to_mode(unsigned int prot); +extern unsigned int mode_to_prot(int mode); extern int affs_fix_hash_pred(struct inode *startino, int startoffset, - __s32 key, __s32 newkey); -extern int affs_fix_link_pred(struct inode *startino, __s32 key, __s32 newkey); + int key, int newkey); +extern int affs_fix_link_pred(struct inode *startino, int key, int newkey); /* bitmap. c */ extern int affs_count_free_blocks(struct super_block *s); -extern int affs_count_free_bits(int blocksize, const __u8 *data); -extern void affs_free_block(struct super_block *sb, __s32 block); -extern __s32 affs_new_header(struct inode *inode); -extern __s32 affs_new_data(struct inode *inode); +extern int affs_count_free_bits(int blocksize, const char *data); +extern void affs_free_block(struct super_block *sb, int block); +extern int affs_new_header(struct inode *inode); +extern int affs_new_data(struct inode *inode); extern void affs_make_zones(struct super_block *sb); /* namei.c */ @@ -78,7 +85,7 @@ extern int affs_notify_change(struct inode *inode, struct iattr *attr); extern void affs_put_inode(struct inode *); extern struct inode *affs_new_inode(const struct inode *dir); extern int affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode, - const char *name, int len, __s32 type); + const char *name, int len, int type); /* file.c */ @@ -101,5 +108,4 @@ extern struct inode_operations affs_chrdev_inode_operations; extern struct inode_operations affs_blkdev_inode_operations; extern int init_affs_fs(void); - #endif diff --git a/include/linux/affs_fs_i.h b/include/linux/affs_fs_i.h index 62785ba3ea29..7230f0a3523a 100644 --- a/include/linux/affs_fs_i.h +++ b/include/linux/affs_fs_i.h @@ -1,24 +1,25 @@ #ifndef _AFFS_FS_I #define _AFFS_FS_I -#define EXT_CACHE_SIZE 16 +#define EXT_CACHE_SIZE 12 #define MAX_PREALLOC 8 /* MUST be a power of 2 */ /* * affs fs inode data in memory */ struct affs_inode_info { - int i_protect; /* unused attribute bits */ - int i_parent; /* parent ino */ - int i_original; /* if != 0, this is the key of the original */ - __u32 i_ext[EXT_CACHE_SIZE]; /* extension block numbers */ - __u32 i_data[MAX_PREALLOC]; /* preallocated blocks */ - short i_max_ext; /* last known extension block */ - short i_pa_cnt; /* number of preallocated blocks */ - short i_pa_next; /* Index of next block in i_data[] */ - short i_pa_last; /* Index of next free slot in i_data[] */ - short i_zone; /* write zone */ - unsigned char i_hlink; /* This is a fake */ + __u32 i_protect; /* unused attribute bits */ + __s32 i_parent; /* parent ino */ + __s32 i_original; /* if != 0, this is the key of the original */ + __s32 i_ext[EXT_CACHE_SIZE]; /* extension block numbers */ + __s32 i_data[MAX_PREALLOC]; /* preallocated blocks */ + int i_lastblock; /* last allocated block */ + short i_max_ext; /* last known extension block */ + short i_pa_cnt; /* number of preallocated blocks */ + short i_pa_next; /* Index of next block in i_data[] */ + short i_pa_last; /* Index of next free slot in i_data[] */ + short i_zone; /* write zone */ + unsigned char i_hlink; /* This is a fake */ unsigned char i_pad; }; diff --git a/include/linux/affs_fs_sb.h b/include/linux/affs_fs_sb.h index 87d41c0d5dde..7d73710c95ed 100644 --- a/include/linux/affs_fs_sb.h +++ b/include/linux/affs_fs_sb.h @@ -8,24 +8,30 @@ * */ -#include - #define MAX_ZONES 8 -#define AFFS_DATA_MIN_FREE 30 /* Percentage of free blocks needed for a data zone */ -#define AFFS_HDR_MIN_FREE 10 /* Same for header blocks */ +#define AFFS_DATA_MIN_FREE 512 /* Number of free blocks in zone for data blocks */ +#define AFFS_HDR_MIN_FREE 128 /* Same for header blocks */ +#define AFFS_ZONE_SIZE 1024 /* Blocks per alloc zone, must be multiple of 32 */ struct affs_bm_info { - struct buffer_head *bm_bh; /* Buffer for bitmap. */ - int bm_free; /* Free blocks. */ - int bm_size; /* Size in bits, rounded to multiple of 32. */ + struct buffer_head *bm_bh; /* Buffer head if loaded (bm_count > 0) */ int bm_firstblk; /* Block number of first bit in this map */ + int bm_key; /* Disk block number */ + int bm_count; /* Usage counter */ +}; + +struct affs_alloc_zone { + short az_size; /* Size of this allocation zone in double words */ + short az_count; /* Number of users */ + int az_free; /* Free blocks in here (no. of bits) */ }; struct affs_zone { unsigned long z_ino; /* Associated inode number */ struct affs_bm_info *z_bm; /* Zone lies in this bitmap */ int z_start; /* Index of first word in bitmap */ - int z_zone_no; /* Zone number */ + int z_end; /* Index of last word in zone + 1 */ + int z_az_no; /* Zone number */ unsigned long z_lru_time; /* Time of last usage */ }; @@ -42,10 +48,11 @@ struct affs_sb_info { struct affs_bm_info *s_bitmap; /* Bitmap infos. */ int s_bm_count; /* Number of bitmap blocks. */ int s_nextzone; /* Next zone to look for free blocks. */ - int s_num_zones; /* Total number of zones. */ - struct affs_zone *s_zones; /* The zones themselves. */ - char *s_zonemap; /* Bitmap for zones. */ - char *s_prefix; /* Prefix for volumes and assigns. */ + int s_num_az; /* Total number of alloc zones. */ + struct affs_zone *s_zones; /* The zones themselfes. */ + struct affs_alloc_zone *s_alloc;/* The allocation zones. */ + char *s_zonemap; /* Bitmap for allocation zones. */ + char *s_prefix; /* Prefix for volumes and assignes. */ int s_prefix_len; /* Length of prefix. */ char s_volume[32]; /* Volume prefix for absolute symlinks. */ }; diff --git a/include/linux/affs_hardblocks.h b/include/linux/affs_hardblocks.h index f7c943e9b29e..33315488dc54 100644 --- a/include/linux/affs_hardblocks.h +++ b/include/linux/affs_hardblocks.h @@ -3,10 +3,6 @@ /* Just the needed definitions for the RDB of an Amiga HD. */ -#ifndef AMIGAFFS_H -#include -#endif - struct RigidDiskBlock { __u32 rdb_ID; __u32 rdb_SummedLongs; diff --git a/include/linux/amigaffs.h b/include/linux/amigaffs.h index 30d62360ed04..679f333e5442 100644 --- a/include/linux/amigaffs.h +++ b/include/linux/amigaffs.h @@ -8,7 +8,7 @@ #define GET_END_PTR(st,p,sz) ((st *)((char *)(p)+((sz)-sizeof(st)))) #define AFFS_GET_HASHENTRY(data,hashkey) htonl(((struct dir_front *)data)->hashtable[hashkey]) -#define AFFS_BLOCK(data,ino,blk) ((struct file_front *)data)->blocks[AFFS_I2HSIZE(ino)-1-blk] +#define AFFS_BLOCK(data,ino,blk) ((struct file_front *)data)->blocks[AFFS_I2HSIZE(ino)-1-(blk)] #define FILE_END(p,i) GET_END_PTR(struct file_end,p,AFFS_I2BSIZE(i)) #define ROOT_END(p,i) GET_END_PTR(struct root_end,p,AFFS_I2BSIZE(i)) @@ -29,8 +29,6 @@ #error Endianness must be known for affs to work. #endif -/* The following constants will be checked against the values read native */ - #define FS_OFS 0x444F5300 #define FS_FFS 0x444F5301 #define FS_INTLOFS 0x444F5302 @@ -45,13 +43,6 @@ #define MUFS_DCOFS 0x6d754604 /* 'muF\4' */ #define MUFS_DCFFS 0x6d754605 /* 'muF\5' */ -struct DateStamp -{ - __u32 ds_Days; - __u32 ds_Minute; - __u32 ds_Tick; -}; - #define T_SHORT 2 #define T_LIST 16 #define T_DATA 8 @@ -66,121 +57,132 @@ struct DateStamp struct root_front { __s32 primary_type; - __u32 spare1[2]; - __u32 hash_size; - __u32 spare2; + __s32 spare1[2]; + __s32 hash_size; + __s32 spare2; __u32 checksum; - __u32 hashtable[0]; + __s32 hashtable[0]; }; struct root_end { __s32 bm_flag; - __u32 bm_keys[25]; - __u32 bm_extend; + __s32 bm_keys[25]; + __s32 bm_extend; struct DateStamp dir_altered; __u8 disk_name[40]; struct DateStamp disk_altered; struct DateStamp disk_made; - __u32 spare1[3]; + __s32 spare1[3]; __s32 secondary_type; }; struct dir_front { __s32 primary_type; - __u32 own_key; - __u32 spare1[3]; + __s32 own_key; + __s32 spare1[3]; __u32 checksum; - __u32 hashtable[0]; + __s32 hashtable[0]; }; struct dir_end { - __u32 spare1; - __u16 owner_uid; - __u16 owner_gid; + __s32 spare1; + __s16 owner_uid; + __s16 owner_gid; __u32 protect; - __u32 spare2; + __s32 spare2; __u8 comment[92]; struct DateStamp created; __u8 dir_name[32]; - __u32 spare3[2]; - __u32 link_chain; - __u32 spare4[5]; - __u32 hash_chain; - __u32 parent; - __u32 spare5; + __s32 spare3[2]; + __s32 link_chain; + __s32 spare4[5]; + __s32 hash_chain; + __s32 parent; + __s32 spare5; __s32 secondary_type; }; struct file_front { __s32 primary_type; - __u32 own_key; - __u32 block_count; - __u32 unknown1; - __u32 first_data; + __s32 own_key; + __s32 block_count; + __s32 unknown1; + __s32 first_data; __u32 checksum; - __u32 blocks[0]; + __s32 blocks[0]; }; struct file_end { - __u32 spare1; - __u16 owner_uid; - __u16 owner_gid; + __s32 spare1; + __s16 owner_uid; + __s16 owner_gid; __u32 protect; - __u32 byte_size; + __s32 byte_size; __u8 comment[92]; struct DateStamp created; __u8 file_name[32]; - __u32 spare2; - __u32 original; /* not really in file_end */ - __u32 link_chain; - __u32 spare3[5]; - __u32 hash_chain; - __u32 parent; - __u32 extension; + __s32 spare2; + __s32 original; /* not really in file_end */ + __s32 link_chain; + __s32 spare3[5]; + __s32 hash_chain; + __s32 parent; + __s32 extension; __s32 secondary_type; }; struct hlink_front { __s32 primary_type; - __u32 own_key; - __u32 spare1[3]; + __s32 own_key; + __s32 spare1[3]; __u32 checksum; }; struct hlink_end { - __u32 spare1; - __u16 owner_uid; - __u16 owner_gid; + __s32 spare1; + __s16 owner_uid; + __s16 owner_gid; __u32 protect; __u8 comment[92]; struct DateStamp created; __u8 link_name[32]; - __u32 spare2; - __u32 original; - __u32 link_chain; - __u32 spare3[5]; - __u32 hash_chain; - __u32 parent; - __u32 spare4; + __s32 spare2; + __s32 original; + __s32 link_chain; + __s32 spare3[5]; + __s32 hash_chain; + __s32 parent; + __s32 spare4; __s32 secondary_type; }; struct slink_front { __s32 primary_type; - __u32 own_key; - __u32 spare1[3]; - __u32 checksum; + __s32 own_key; + __s32 spare1[3]; + __s32 checksum; __u8 symname[288]; /* depends on block size */ }; +struct data_front +{ + __s32 primary_type; + __s32 header_key; + __s32 sequence_number; + __s32 data_size; + __s32 next_data; + __s32 checksum; + __u8 data[488]; /* depends on block size */ +}; + /* Permission bits */ #define FIBF_OTR_READ 0x8000 diff --git a/include/linux/aztcd.h b/include/linux/aztcd.h index 6154a992dc8e..71fe5a0df545 100644 --- a/include/linux/aztcd.h +++ b/include/linux/aztcd.h @@ -1,4 +1,4 @@ -/* $Id: aztcd.h,v 2.30 1996/04/26 05:33:56 root Exp root $ +/* $Id: aztcd.h,v 2.50 1996/05/17 16:15:43 root Exp root $ * * Definitions for a AztechCD268 CD-ROM interface * Copyright (C) 1994, 1995 Werner Zimmermann @@ -32,7 +32,7 @@ */ #ifdef AZT_SW32 -#define AZT_SW32_BASE_ADDR 0x220 /*I/O port base address of your soundcard*/ +#define AZT_SW32_BASE_ADDR 0x220 /*I/O port base address of your soundcard*/ #endif /* Set this to 1, if you want your tray to be locked, set to 0 to prevent tray @@ -74,9 +74,9 @@ #define STATUS_PORT azt_port+1 #define MODE_PORT azt_port+2 #ifdef AZT_SW32 - #define AZT_SW32_INIT (unsigned int) (0xFF00 & (AZT_BASE_ADDR*16)) - #define AZT_SW32_CONFIG_REG AZT_SW32_BASE_ADDR+0x16 /*Soundwave32 Config. Register*/ - #define AZT_SW32_ID_REG AZT_SW32_BASE_ADDR+0x04 /*Soundwave32 ID Version Register*/ + #define AZT_SW32_INIT (unsigned int) (0xFF00 & (AZT_BASE_ADDR*16)) + #define AZT_SW32_CONFIG_REG AZT_SW32_BASE_ADDR+0x16 /*Soundwave32 Config. Register*/ + #define AZT_SW32_ID_REG AZT_SW32_BASE_ADDR+0x04 /*Soundwave32 ID Version Register*/ #endif /* status bits */ diff --git a/include/linux/isdn.h b/include/linux/isdn.h index bc33fa1771f4..a569192789a9 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -1,4 +1,4 @@ -/* $Id: isdn.h,v 1.3 1996/04/20 16:54:58 fritz Exp $ +/* $Id: isdn.h,v 1.10 1996/05/18 01:37:18 fritz Exp $ * * Main header for the Linux ISDN subsystem (linklevel). * @@ -21,6 +21,29 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn.h,v $ + * Revision 1.10 1996/05/18 01:37:18 fritz + * Added spelling corrections and some minor changes + * to stay in sync with kernel. + * + * Revision 1.9 1996/05/17 03:58:20 fritz + * Added flags for DLE handling. + * + * Revision 1.8 1996/05/11 21:49:55 fritz + * Removed queue mamagement variables. + * Changed queue management to use sk_buffs. + * + * Revision 1.7 1996/05/07 09:10:06 fritz + * Reorganized tty-related structs. + * + * Revision 1.6 1996/05/06 11:38:27 hipp + * minor change in ippp struct + * + * Revision 1.5 1996/04/30 11:03:16 fritz + * Added Michael's ippp-bind patch. + * + * Revision 1.4 1996/04/29 23:00:02 fritz + * Added variables for voice-support. + * * Revision 1.3 1996/04/20 16:54:58 fritz * Increased maximum number of channels. * Added some flags for isdn_net to handle callback more reliable. @@ -110,7 +133,7 @@ #define ISDN_USAGE_EXCLUSIVE 64 /* This bit is set, if channel is exclusive */ #define ISDN_USAGE_OUTGOING 128 /* This bit is set, if channel is outgoing */ -#define ISDN_MODEM_ANZREG 20 /* Number of Modem-Registers */ +#define ISDN_MODEM_ANZREG 21 /* Number of Modem-Registers */ #define ISDN_MSNLEN 20 typedef struct { @@ -150,6 +173,7 @@ typedef struct { int secure; /* Flag: Secure */ int callback; /* Flag: Callback */ int cbhup; /* Flag: Reject Call before Callback */ + int pppbind; /* ippp device for bindings */ } isdn_net_ioctl_cfg; #ifdef __KERNEL__ @@ -214,11 +238,14 @@ typedef struct { #define ISDN_SERVICE_BTEL 1<<12 /* Macros checking plain usage */ -#define USG_NONE(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_NONE) -#define USG_RAW(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_RAW) -#define USG_MODEM(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_MODEM) -#define USG_NET(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_NET) -#define USG_OUTGOING(x) ((x & ISDN_USAGE_OUTGOING)==ISDN_USAGE_OUTGOING) +#define USG_NONE(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_NONE) +#define USG_RAW(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_RAW) +#define USG_MODEM(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_MODEM) +#define USG_VOICE(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE) +#define USG_NET(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_NET) +#define USG_OUTGOING(x) ((x & ISDN_USAGE_OUTGOING)==ISDN_USAGE_OUTGOING) +#define USG_MODEMORVOICE(x) (((x & ISDN_USAGE_MASK)==ISDN_USAGE_MODEM) || \ + ((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE) ) /* Timer-delays and scheduling-flags */ #define ISDN_TIMER_RES 3 /* Main Timer-Resolution */ @@ -333,6 +360,7 @@ typedef struct isdn_net_local_s { /* Ptr to orig. header_cache_update */ void (*org_hcu)(struct hh_cache *, struct device *, unsigned char *); + int pppbind; /* ippp device for bindings */ } isdn_net_local; #ifdef CONFIG_ISDN_PPP @@ -375,70 +403,74 @@ typedef struct isdn_net_dev_s { #define ISDN_ASYNC_PGRP_LOCKOUT 0x0200 /* Lock cua opens on pgrp */ #define ISDN_ASYNC_CALLOUT_NOHUP 0x0400 /* No hangup for cui */ #define ISDN_ASYNC_SPLIT_TERMIOS 0x0008 /* Sep. termios for dialin/out */ -#define ISDN_PORT_16550A 4 /* Type of faked Hardware */ #define ISDN_SERIAL_XMIT_SIZE 4000 /* Maximum bufsize for write */ -#define ISDN_SERIAL_TYPE_NORMAL 1 /* tty-type */ -#define ISDN_SERIAL_TYPE_CALLOUT 2 /* cua-type */ +#define ISDN_SERIAL_TYPE_NORMAL 1 +#define ISDN_SERIAL_TYPE_CALLOUT 2 + +/* Private data of AT-command-interpreter */ +typedef struct atemu { + u_char profile[ISDN_MODEM_ANZREG]; /* Modem-Regs. Profile 0 */ + u_char mdmreg[ISDN_MODEM_ANZREG]; /* Modem-Registers */ + char pmsn[ISDN_MSNLEN]; /* EAZ/MSNs Profile 0 */ + char msn[ISDN_MSNLEN];/* EAZ/MSN */ + u_char vpar[10]; /* Voice-parameters */ + int mdmcmdl; /* Length of Modem-Commandbuffer */ + int pluscount; /* Counter for +++ sequence */ + int lastplus; /* Timestamp of last + */ + int lastDLE; /* Flag for voice-coding: DLE seen */ + char mdmcmd[255]; /* Modem-Commandbuffer */ +} atemu; /* Private data (similar to async_struct in ) */ -typedef struct { +typedef struct modem_info { int magic; int flags; /* defined in tty.h */ - int type; /* UART type */ - struct tty_struct *tty; int x_char; /* xon/xoff character */ - int close_delay; - int MCR; /* Modem control register */ + int mcr; /* Modem control register */ + int msr; /* Modem status register */ + int lsr; /* Line status register */ int line; int count; /* # of fd on device */ int blocked_open; /* # of blocked opens */ long session; /* Session of opening process */ long pgrp; /* pgrp of opening process */ + int online; /* B-Channel is up */ + int vonline; /* Voice-channel status */ + int dialing; /* Dial in progress */ + int rcvsched; /* Receive needs schedule */ int isdn_driver; /* Index to isdn-driver */ int isdn_channel; /* Index to isdn-channel */ int drv_index; /* Index to dev->usage */ + int ncarrier; /* Flag: schedule NO CARRIER */ + struct timer_list nc_timer; /* Timer for delayed NO CARRIER */ +#define FUTURE 1 #if FUTURE int send_outstanding;/* # of outstanding send-requests */ #endif int xmit_size; /* max. # of chars in xmit_buf */ int xmit_count; /* # of chars in xmit_buf */ - u_char *xmit_buf; /* transmit-buffer */ - struct termios normal_termios; + struct tty_struct *tty; /* Pointer to corresponding tty */ + atemu emu; /* AT-emulator data */ + void *adpcms; /* state for adpcm decompression */ + void *adpcmr; /* state for adpcm compression */ + struct termios normal_termios; /* For saving termios structs */ struct termios callout_termios; struct wait_queue *open_wait; struct wait_queue *close_wait; + struct sk_buff_head *xmit_buf; /* transmit-buffer queue */ } modem_info; #define ISDN_MODEM_WINSIZE 8 -/* Private data of AT-command-interpreter */ -typedef struct { - u_char profile[ISDN_MODEM_ANZREG]; /* Modem-Regs. Profile 0 */ - u_char mdmreg[ISDN_MODEM_ANZREG]; /* Modem-Registers */ - char pmsn[ISDN_MSNLEN]; /* EAZ/MSNs Profile 0 */ - char msn[ISDN_MSNLEN];/* EAZ/MSN */ - int mdmcmdl; /* Length of Modem-Commandbuffer */ - int pluscount; /* Counter for +++ sequence */ - int lastplus; /* Timestamp of last + */ - char mdmcmd[255]; /* Modem-Commandbuffer */ -} atemu; - /* Description of one ISDN-tty */ typedef struct { - int msr[ISDN_MAX_CHANNELS]; /* Modem-statusregister */ - int mlr[ISDN_MAX_CHANNELS]; /* Line-statusregister */ - int refcount; /* Number of opens */ - int online[ISDN_MAX_CHANNELS]; /* B-Channel is up */ - int dialing[ISDN_MAX_CHANNELS]; /* Dial in progress */ - int rcvsched[ISDN_MAX_CHANNELS]; /* Receive needs schedule */ - int ncarrier[ISDN_MAX_CHANNELS]; /* Output NO CARRIER */ - struct tty_driver tty_modem; /* tty-device */ - struct tty_driver cua_modem; /* cua-device */ + int refcount; /* Number of opens */ + struct tty_driver tty_modem; /* tty-device */ + struct tty_driver cua_modem; /* cua-device */ struct tty_struct *modem_table[ISDN_MAX_CHANNELS]; /* ?? copied from Orig */ - struct termios *modem_termios[ISDN_MAX_CHANNELS]; - struct termios *modem_termios_locked[ISDN_MAX_CHANNELS]; - atemu atmodem[ISDN_MAX_CHANNELS]; /* AT-Command-parser */ - modem_info info[ISDN_MAX_CHANNELS]; /* Private data */ + struct termios modem_termios[ISDN_MAX_CHANNELS]; + struct termios modem_termios_locked[ISDN_MAX_CHANNELS]; + modem_info info[ISDN_MAX_CHANNELS]; /* Private data */ } modem; /*======================= End of ISDN-tty stuff ============================*/ @@ -504,6 +536,7 @@ struct ippp_struct { unsigned char *cbuf; struct slcompress *slcomp; #endif + unsigned long debug; }; #endif @@ -512,15 +545,6 @@ struct ippp_struct { /*======================= Start of general stuff ===========================*/ -/* Packet-queue-element */ -typedef struct pqueue { - char *next; /* Pointer to next packet */ - short length; /* Packetlength */ - short size; /* Allocated size */ - u_char *rptr; /* Read-pointer for stream-reading */ - u_char buffer[1]; /* The data (will be alloc'd) */ -} pqueue; - typedef struct { char *next; char *private; @@ -540,7 +564,8 @@ typedef struct { isdn_if *interface; /* Interface to driver */ int *rcverr; /* Error-counters for B-Ch.-receive */ int *rcvcount; /* Byte-counters for B-Ch.-receive */ - pqueue **rpqueue; /* Pointers to start of Rcv-Queue */ + unsigned long DLEflag; /* Flags: Insert DLE at next read */ + struct sk_buff_head *rpqueue; /* Pointers to start of Rcv-Queue */ struct wait_queue **rcv_waitq; /* Wait-Queues for B-Channel-Reads */ struct wait_queue **snd_waitq; /* Wait-Queue for B-Channel-Send's */ char msn2eaz[10][ISDN_MSNLEN]; /* Mapping-Table MSN->EAZ */ diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h index b14fec067120..5ce86f868e27 100644 --- a/include/linux/isdn_ppp.h +++ b/include/linux/isdn_ppp.h @@ -1,4 +1,8 @@ +#ifndef _LINUX_ISDN_PPP_H +#define _LINUX_ISDN_PPP_H + extern int isdn_ppp_dial_slave(char *); +extern int isdn_ppp_hangup_slave(char *); struct pppinfo { @@ -28,3 +32,4 @@ struct pppinfo #define MP_END_FRAG 0x40 #define MP_BEGIN_FRAG 0x80 +#endif diff --git a/include/linux/isdnif.h b/include/linux/isdnif.h index 875fc8148f9c..596192ba81a5 100644 --- a/include/linux/isdnif.h +++ b/include/linux/isdnif.h @@ -1,4 +1,4 @@ -/* $Id: isdnif.h,v 1.2 1996/04/20 17:02:40 fritz Exp $ +/* $Id: isdnif.h,v 1.8 1996/05/18 01:45:37 fritz Exp $ * * Linux ISDN subsystem * @@ -22,6 +22,27 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdnif.h,v $ + * Revision 1.8 1996/05/18 01:45:37 fritz + * More spelling corrections. + * + * Revision 1.7 1996/05/18 01:37:19 fritz + * Added spelling corrections and some minor changes + * to stay in sync with kernel. + * + * Revision 1.6 1996/05/17 03:59:28 fritz + * Marked rcvcallb and writebuf obsolete. + * + * Revision 1.5 1996/05/01 11:43:54 fritz + * Removed STANDALONE + * + * Revision 1.4 1996/05/01 11:38:40 fritz + * Added ISDN_FEATURE_L2_TRANS + * + * Revision 1.3 1996/04/29 22:57:54 fritz + * Added driverId and channel parameters to + * writecmd() and readstat(). + * Added constant for voice-support. + * * Revision 1.2 1996/04/20 17:02:40 fritz * Changes to support skbuffs for Lowlevel-Drivers. * Misc. typos @@ -34,10 +55,6 @@ #ifndef isdnif_h #define isdnif_h -#ifdef STANDALONE -#include -#endif - /* * Values for general protocol-selection */ @@ -52,6 +69,7 @@ #define ISDN_PROTO_L2_X75UI 1 /* X75/LAPB with UI-Frames */ #define ISDN_PROTO_L2_X75BUI 2 /* X75/LAPB with UI-Frames */ #define ISDN_PROTO_L2_HDLC 3 /* HDLC */ +#define ISDN_PROTO_L2_TRANS 4 /* Transparent (Voice) */ /* * Values for Layer-3-protocol-selection @@ -112,6 +130,7 @@ #define ISDN_FEATURE_L2_X75UI (0x0001 << ISDN_PROTO_L2_X75UI) #define ISDN_FEATURE_L2_X75BUI (0x0001 << ISDN_PROTO_L2_X75BUI) #define ISDN_FEATURE_L2_HDLC (0x0001 << ISDN_PROTO_L2_HDLC) +#define ISDN_FEATURE_L2_TRANS (0x0001 << ISDN_PROTO_L2_TRANS) /* Layer 3 */ #define ISDN_FEATURE_L3_TRANS (0x0100 << ISDN_PROTO_L3_TRANS) @@ -167,6 +186,10 @@ typedef struct { * int local channel-number (0 ...) * u_char pointer to received data (in Kernel-Space, volatile) * int length of data + * + * NOTE: This callback is obsolete, and will be removed when all + * current LL-drivers support rcvcall_skb. Do NOT use for new + * drivers. */ void (*rcvcallb)(int, int, u_char*, int); @@ -207,6 +230,10 @@ typedef struct { * no schedule allowed) * 1 = Data is in User-Space (use memcpy_fromfs, * may schedule) + * + * NOTE: This call is obsolete, and will be removed when all + * current LL-drivers support writebuf_skb. Do NOT use for new + * drivers. */ int (*writebuf)(int, int, const u_char*, int, int); @@ -227,8 +254,10 @@ typedef struct { * no schedule allowed) * 1 = Data is in User-Space (use memcpy_fromfs, * may schedule) + * int driverId + * int local channel-number (0 ...) */ - int (*writecmd)(const u_char*, int, int); + int (*writecmd)(const u_char*, int, int, int, int); /* Read raw Status replies * u_char pointer data (volatile) * int length of buffer @@ -236,8 +265,10 @@ typedef struct { * no schedule allowed) * 1 = Data is in User-Space (use memcpy_fromfs, * may schedule) + * int driverId + * int local channel-number (0 ...) */ - int (*readstat)(u_char*, int, int); + int (*readstat)(u_char*, int, int, int, int); char id[20]; } isdn_if; @@ -250,7 +281,7 @@ typedef struct { * supporting sk_buff's should set this to 0. * command Address of Command-Handler. * features Bitwise coded Features of this driver. (use ISDN_FEATURE_...) - * writebuf Address of Send-Command-Handler. + * writebuf Address of Send-Command-Handler. OBSOLETE do NOT use anymore. * writebuf_skb Address of Skbuff-Send-Handler. (NULL if not supported) * writecmd " " D-Channel " which accepts raw D-Ch-Commands. * readstat " " D-Channel " which delivers raw Status-Data. @@ -259,7 +290,7 @@ typedef struct { * * channels Driver-ID assigned to this driver. (Must be used on all * subsequent callbacks. - * rcvcallb Address of handler for received data. + * rcvcallb Address of handler for received data. OBSOLETE, do NOT use anymore. * rcvcallb_skb Address of handler for received Skbuff's. (NULL if not supp.) * statcallb " " " for status-changes. * diff --git a/include/linux/mcdx.h b/include/linux/mcdx.h index 9fb518643c24..cce1a7f006c6 100644 --- a/include/linux/mcdx.h +++ b/include/linux/mcdx.h @@ -27,7 +27,7 @@ * Daniel v. Mosnenck (he sent me the Technical and Programming Reference) * Gerd Knorr (he lent me his PhotoCD) * Nils Faerber and Roger E. Wolff (extensively tested the LU portion) - * Andreas Kies (testing the mysterious hang up's) + * Andreas Kies (testing the mysterious hangups) * ... somebody forgotten? * */ @@ -35,14 +35,14 @@ #ifndef __MCDX_H #define __MCDX_H /* - * PLEASE CONFIGURE THIS ACCORIDNG TO YOURS HARDWARE/JUMPER SETTINGS. + * PLEASE CONFIGURE THIS ACCORDING TO YOUR HARDWARE/JUMPER SETTINGS. * * o MCDX_NDRIVES : number of used entries of the following table * o MCDX_DRIVEMAP : table of {i/o base, irq} per controller * * NOTE: Don't even think about connecting the drive to IRQ 9(2). * In the AT architecture this interrupt is used to cascade the two - * interrupt controllers and isn't therefore usable for enything else! + * interrupt controllers and isn't therefore usable for anything else! */ /* #define I_WAS_IN_MCDX_H */ #define MCDX_NDRIVES 1 @@ -55,11 +55,11 @@ /* * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!NO USER INTERVENTION NEEDED BELOW - * If You are shure that all configuration is done, please uncomment the + * If You are sure that all configuration is done, please uncomment the * line below. */ -#undef MCDX_DEBUG /* This is *REALLY* only for developement! */ +#undef MCDX_DEBUG /* This is *REALLY* only for development! */ #ifdef MCDX_DEBUG #define MCDX_TRACE(x) printk x diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index d5a7688678ed..80776ef17438 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -120,7 +120,8 @@ enum scsi_directory_inos { PROC_SCSI_GENERIC_NCR5380, PROC_SCSI_IN2000, PROC_SCSI_PAS16, - PROC_SCSI_QLOGIC, + PROC_SCSI_QLOGICFAS, + PROC_SCSI_QLOGICISP, PROC_SCSI_SEAGATE, PROC_SCSI_T128, PROC_SCSI_NCR53C7xx, diff --git a/include/net/sock.h b/include/net/sock.h index 6d87400e8f46..fdcd6fd81e56 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -195,8 +195,8 @@ struct sock struct sock *next; struct sock *prev; /* Doubly linked chain.. */ struct sock *pair; - struct sk_buff * send_head; - struct sk_buff * send_tail; + struct sk_buff * volatile send_head; + struct sk_buff * volatile send_tail; struct sk_buff_head back_log; struct sk_buff *partial; struct timer_list partial_timer; @@ -212,33 +212,33 @@ struct sock unsigned short window; __u32 lastwin_seq; /* sequence number when we last updated the window we offer */ __u32 high_seq; /* sequence number when we did current fast retransmit */ - unsigned long ato; /* ack timeout */ - unsigned long lrcvtime; /* jiffies at last rcv */ + volatile unsigned long ato; /* ack timeout */ + volatile unsigned long lrcvtime; /* jiffies at last rcv */ unsigned short bytes_rcv; /* * mss is min(mtu, max_window) */ unsigned short mtu; /* mss negotiated in the syn's */ - unsigned short mss; /* current eff. mss - can change */ - unsigned short user_mss; /* mss requested by user in ioctl */ - unsigned short max_window; + volatile unsigned short mss; /* current eff. mss - can change */ + volatile unsigned short user_mss; /* mss requested by user in ioctl */ + volatile unsigned short max_window; unsigned long window_clamp; unsigned int ssthresh; unsigned short num; - unsigned short cong_window; - unsigned short cong_count; - unsigned short packets_out; - unsigned short shutdown; - unsigned long rtt; - unsigned long mdev; - unsigned long rto; + volatile unsigned short cong_window; + volatile unsigned short cong_count; + volatile unsigned short packets_out; + volatile unsigned short shutdown; + volatile unsigned long rtt; + volatile unsigned long mdev; + volatile unsigned long rto; /* * currently backoff isn't used, but I'm maintaining it in case * we want to go back to a backoff formula that needs it */ - unsigned short backoff; + volatile unsigned short backoff; int err, err_soft; /* Soft holds errors that don't cause failure but are the cause of a persistent failure not just diff --git a/kernel/module.c b/kernel/module.c index f40c40a599d9..d3e8a802bf2e 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -293,7 +293,7 @@ sys_delete_module(char *module_name) else { for (mp = module_list; mp != &kernel_module; mp = mp->next) { if ((mp->ref == NULL) && (mp->state == MOD_RUNNING) && - ((GET_USE_COUNT(mp) & ~(MOD_AUTOCLEAN | MOD_VISITED)) == 0)) { + ((GET_USE_COUNT(mp) & ~MOD_VISITED) == MOD_AUTOCLEAN)) { if ((GET_USE_COUNT(mp) & MOD_VISITED)) { /* Don't reap until one "cycle" after last _use_ */ GET_USE_COUNT(mp) &= ~MOD_VISITED; diff --git a/net/core/net_alias.c b/net/core/net_alias.c index b0feb9ee6267..e6f1fe3eb591 100644 --- a/net/core/net_alias.c +++ b/net/core/net_alias.c @@ -235,6 +235,18 @@ net_alias_hard_start_xmit(struct sk_buff *skb, struct device *dev) } +static int +net_alias_open(struct device * dev) +{ + return 0; +} + +static int +net_alias_close(struct device * dev) +{ + return 0; +} + /* * setups a new (alias) device */ @@ -264,6 +276,8 @@ net_alias_devsetup(struct net_alias *alias, struct net_alias_type *nat, dev->my_alias = alias; /* point to alias */ dev->name = alias->name; dev->type = main_dev->type; + dev->open = net_alias_open; + dev->stop = net_alias_close; dev->hard_header_len = main_dev->hard_header_len; memcpy(dev->broadcast, main_dev->broadcast, MAX_ADDR_LEN); memcpy(dev->dev_addr, main_dev->dev_addr, MAX_ADDR_LEN); diff --git a/net/decnet/README b/net/decnet/README index 6f60472b26fe..96816c47cc52 100644 --- a/net/decnet/README +++ b/net/decnet/README @@ -1,4 +1,4 @@ -Yes.. its being worked on. +Yes.. it's being worked on. If you want to get involved email me and I'll put you in touch with the people doing the work. diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3a461bfe87c8..c1635c9df564 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -61,15 +61,7 @@ extern __inline__ void tcp_delack_estimator(struct sock *sk) if (m <= 0) m = 1; - /* Yikes. This used to test if m was larger than rtt/8. - * Maybe on a long delay high speed link this would be - * good initial guess, but over a slow link where the - * delay is dominated by transmission time this will - * be very bad, since ato will almost always be something - * more like rtt/2. Better to discard data points that - * are larger than the rtt estimate. - */ - if (m > sk->rtt) + if (m > (sk->rtt >> 3)) { sk->ato = sk->rtt >> 3; /* @@ -741,7 +733,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) * (2) it has the same window as the last ACK, * (3) we have outstanding data that has not been ACKed * (4) The packet was not carrying any data. - * (5) [From Floyds paper on fast retransmit wars] + * (5) [From Floyd's paper on fast retransmit wars] * The packet acked data after high_seq; * I've tried to order these in occurrence of most likely to fail * to least likely to fail. diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 0f2051bc2cb4..e26154b7826a 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -837,7 +837,7 @@ void tcp_send_synack(struct sock * newsk, struct sock * sk, struct sk_buff * skb * sending every two full sized packets will never need to be * invoked, the delayed ack will be sent before the ATO timeout * every time. Of course, the relies on our having a good estimate - * for packet interarrival times. + * for packet interarrival times.) */ void tcp_send_delayed_ack(struct sock * sk, int max_timeout, unsigned long timeout) { -- 2.39.5